nautobot 3.0.0a2__py3-none-any.whl → 3.0.0a3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/choices.py +0 -2
- nautobot/apps/filters.py +7 -9
- nautobot/apps/models.py +2 -2
- nautobot/apps/ui.py +9 -1
- nautobot/circuits/filters.py +3 -2
- nautobot/circuits/navigation.py +3 -2
- nautobot/circuits/templates/circuits/circuit.html +1 -1
- nautobot/circuits/templates/circuits/circuit_create.html +3 -3
- nautobot/circuits/templates/circuits/circuittermination.html +1 -1
- nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
- nautobot/circuits/templates/circuits/circuittype.html +1 -1
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
- nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
- nautobot/circuits/templates/circuits/providernetwork.html +1 -1
- nautobot/circuits/tests/integration/test_circuit.py +10 -13
- nautobot/cloud/filters.py +1 -1
- nautobot/cloud/navigation.py +3 -2
- nautobot/core/api/schema.py +1 -1
- nautobot/core/api/serializers.py +6 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/views.py +8 -0
- nautobot/core/apps/__init__.py +11 -10
- nautobot/core/celery/__init__.py +3 -5
- nautobot/core/checks.py +46 -0
- nautobot/core/cli/bootstrap_v3_to_v5.py +70 -1
- nautobot/core/cli/migrate_deprecated_templates.py +200 -0
- nautobot/core/constants.py +3 -0
- nautobot/core/context_processors.py +9 -1
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/jobs/__init__.py +6 -3
- nautobot/core/jobs/groups.py +31 -1
- nautobot/core/management/commands/generate_test_data.py +28 -9
- nautobot/core/models/generics.py +9 -1
- nautobot/core/models/tree_queries.py +10 -5
- nautobot/core/settings.py +18 -12
- nautobot/core/settings.yaml +13 -7
- nautobot/core/signals.py +12 -1
- nautobot/core/tables.py +13 -6
- nautobot/core/templates/40x.html +1 -1
- nautobot/core/templates/500.html +2 -2
- nautobot/core/templates/admin/config/config.html +12 -12
- nautobot/core/templates/admin/index.html +3 -3
- nautobot/core/templates/buttons/export.html +1 -1
- nautobot/core/templates/components/button/dropdown.html +5 -3
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/components/panel/panel.html +3 -3
- nautobot/core/templates/components/tab/content_wrapper.html +2 -3
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
- nautobot/core/templates/echarts/echarts.html +1 -1
- nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
- nautobot/core/templates/generic/object_bulk_create.html +4 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
- nautobot/core/templates/generic/object_bulk_remove.html +2 -2
- nautobot/core/templates/generic/object_bulk_update.html +5 -4
- nautobot/core/templates/generic/object_create.html +5 -4
- nautobot/core/templates/generic/object_import.html +2 -1
- nautobot/core/templates/generic/object_list.html +12 -4
- nautobot/core/templates/generic/object_notes.html +5 -3
- nautobot/core/templates/generic/object_retrieve.html +2 -3
- nautobot/core/templates/graphene/graphiql.html +7 -7
- nautobot/core/templates/home.html +1 -1
- nautobot/core/templates/import_success.html +2 -1
- nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/created_updated.html +7 -3
- nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/form_static_field.html +6 -0
- nautobot/core/templates/inc/header.html +1 -1
- nautobot/core/templates/inc/image_attachments.html +2 -1
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/search_panel.html +4 -4
- nautobot/core/templates/login.html +4 -2
- nautobot/core/templates/nautobot_config.py.j2 +6 -5
- nautobot/core/templates/redoc_ui.html +7 -0
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +17 -3
- nautobot/core/templates/system_jobs/import_objects.html +1 -2
- nautobot/core/templates/utilities/confirmation_form.html +2 -2
- nautobot/core/templates/utilities/obj_table.html +10 -2
- nautobot/core/templates/utilities/render_field.html +7 -7
- nautobot/core/templates/utilities/render_jinja2.html +2 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +4 -4
- nautobot/core/templates/utilities/theme_preview.html +16 -3
- nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
- nautobot/core/templatetags/helpers.py +52 -6
- nautobot/core/testing/api.py +68 -9
- nautobot/core/testing/filters.py +0 -23
- nautobot/core/testing/integration.py +23 -10
- nautobot/core/testing/mixins.py +2 -0
- nautobot/core/testing/views.py +4 -0
- nautobot/core/tests/integration/test_app_home.py +34 -30
- nautobot/core/tests/integration/test_app_navbar.py +3 -0
- nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
- nautobot/core/tests/runner.py +9 -1
- nautobot/core/tests/test_api.py +5 -3
- nautobot/core/tests/test_breadcrumbs.py +6 -7
- nautobot/core/tests/test_checks.py +28 -0
- nautobot/core/tests/test_cli.py +40 -0
- nautobot/core/tests/test_config.py +2 -1
- nautobot/core/tests/test_forms.py +55 -13
- nautobot/core/tests/test_jobs.py +75 -1
- nautobot/core/tests/test_nautobot_server.py +2 -0
- nautobot/core/tests/test_navigations.py +76 -1
- nautobot/core/tests/test_patch_social_django.py +42 -0
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +53 -13
- nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
- nautobot/core/tests/test_tree_queries.py +14 -1
- nautobot/core/tests/test_ui.py +1 -1
- nautobot/core/tests/test_utils.py +31 -4
- nautobot/core/tests/test_views.py +159 -31
- nautobot/core/ui/breadcrumbs.py +2 -12
- nautobot/core/ui/choices.py +142 -10
- nautobot/core/ui/constants.py +76 -12
- nautobot/core/ui/object_detail.py +92 -12
- nautobot/core/urls.py +12 -1
- nautobot/core/utils/cache.py +2 -1
- nautobot/core/utils/filtering.py +17 -17
- nautobot/core/utils/lookup.py +3 -8
- nautobot/core/utils/module_loading.py +21 -0
- nautobot/core/utils/patch_social_django.py +128 -0
- nautobot/core/views/__init__.py +38 -1
- nautobot/core/views/generic.py +3 -3
- nautobot/core/views/mixins.py +15 -3
- nautobot/core/views/renderers.py +2 -0
- nautobot/core/views/viewsets.py +2 -1
- nautobot/data_validation/apps.py +1 -5
- nautobot/data_validation/custom_validators.py +4 -4
- nautobot/data_validation/filters.py +1 -1
- nautobot/data_validation/forms.py +40 -0
- nautobot/data_validation/migrations/0001_initial.py +0 -7
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +0 -12
- nautobot/data_validation/models.py +16 -7
- nautobot/data_validation/navigation.py +8 -1
- nautobot/data_validation/tables.py +12 -5
- nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
- nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
- nautobot/data_validation/tests/__init__.py +2 -2
- nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
- nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
- nautobot/data_validation/tests/test_filters.py +8 -6
- nautobot/data_validation/tests/test_models.py +15 -0
- nautobot/data_validation/tests/test_views.py +190 -32
- nautobot/data_validation/urls.py +2 -5
- nautobot/data_validation/views.py +73 -40
- nautobot/dcim/api/serializers.py +0 -13
- nautobot/dcim/apps.py +4 -0
- nautobot/dcim/choices.py +16 -0
- nautobot/dcim/custom_validators.py +84 -0
- nautobot/dcim/filter_mixins.py +353 -4
- nautobot/dcim/{filters/__init__.py → filters.py} +2 -35
- nautobot/dcim/forms.py +1 -1
- nautobot/dcim/migrations/0078_remove_device_location_tenant_name_uniqueness.py +16 -0
- nautobot/dcim/migrations/0079_device_name_data_migration.py +59 -0
- nautobot/dcim/models/device_components.py +81 -68
- nautobot/dcim/models/devices.py +13 -16
- nautobot/dcim/navigation.py +7 -6
- nautobot/dcim/tables/devices.py +3 -0
- nautobot/dcim/tables/template_code.py +14 -14
- nautobot/dcim/templates/dcim/cable.html +2 -61
- nautobot/dcim/templates/dcim/cable_connect.html +28 -112
- nautobot/dcim/templates/dcim/cable_edit.html +2 -5
- nautobot/dcim/templates/dcim/cable_retrieve.html +61 -0
- nautobot/dcim/templates/dcim/cable_trace.html +1 -3
- nautobot/dcim/templates/dcim/cable_update.html +5 -0
- nautobot/dcim/templates/dcim/consoleport.html +6 -5
- nautobot/dcim/templates/dcim/consoleserverport.html +6 -5
- nautobot/dcim/templates/dcim/device/config.html +2 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +1 -1
- nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/device/devicebays.html +1 -1
- nautobot/dcim/templates/dcim/device/frontports.html +1 -1
- nautobot/dcim/templates/dcim/device/interfaces.html +1 -1
- nautobot/dcim/templates/dcim/device/inventory.html +1 -1
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
- nautobot/dcim/templates/dcim/device/modulebays.html +1 -1
- nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/device/powerports.html +1 -1
- nautobot/dcim/templates/dcim/device/rearports.html +1 -1
- nautobot/dcim/templates/dcim/device/status.html +8 -8
- nautobot/dcim/templates/dcim/device/wireless.html +1 -1
- nautobot/dcim/templates/dcim/device.html +1 -1
- nautobot/dcim/templates/dcim/device_component_add.html +2 -2
- nautobot/dcim/templates/dcim/device_create.html +5 -3
- nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
- nautobot/dcim/templates/dcim/device_list.html +73 -10
- nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
- nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
- nautobot/dcim/templates/dcim/frontport.html +9 -8
- nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +26 -6
- nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
- nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -242
- nautobot/dcim/templates/dcim/module/base.html +49 -9
- nautobot/dcim/templates/dcim/module_list.html +57 -8
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
- nautobot/dcim/templates/dcim/platform_create.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +5 -4
- nautobot/dcim/templates/dcim/rack_elevation_list.html +16 -4
- nautobot/dcim/templates/dcim/rack_retrieve.html +33 -15
- nautobot/dcim/templates/dcim/rearport.html +7 -6
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
- nautobot/dcim/templates/dcim/virtualchassis_update.html +14 -6
- nautobot/dcim/tests/integration/test_controller.py +1 -0
- nautobot/dcim/tests/test_api.py +8 -0
- nautobot/dcim/tests/test_custom_validators.py +229 -0
- nautobot/dcim/tests/test_filters.py +12 -6
- nautobot/dcim/tests/test_models.py +63 -4
- nautobot/dcim/tests/test_views.py +63 -22
- nautobot/dcim/urls.py +64 -21
- nautobot/dcim/utils.py +3 -3
- nautobot/dcim/views.py +547 -273
- nautobot/extras/api/views.py +9 -1
- nautobot/extras/choices.py +2 -13
- nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
- nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
- nautobot/extras/{filters/__init__.py → filters.py} +14 -46
- nautobot/extras/forms/forms.py +5 -13
- nautobot/extras/forms/mixins.py +0 -41
- nautobot/extras/management/__init__.py +9 -0
- nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
- nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
- nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
- nautobot/extras/models/__init__.py +1 -2
- nautobot/extras/models/approvals.py +22 -13
- nautobot/extras/models/contacts.py +2 -0
- nautobot/extras/models/groups.py +44 -5
- nautobot/extras/models/jobs.py +59 -1
- nautobot/extras/models/mixins.py +28 -0
- nautobot/extras/models/models.py +13 -0
- nautobot/extras/models/secrets.py +1 -0
- nautobot/extras/models/statuses.py +0 -15
- nautobot/extras/navigation.py +13 -9
- nautobot/extras/plugins/__init__.py +33 -55
- nautobot/extras/plugins/tables.py +3 -3
- nautobot/extras/plugins/urls.py +2 -21
- nautobot/extras/plugins/utils.py +1 -33
- nautobot/extras/plugins/views.py +0 -4
- nautobot/extras/signals.py +20 -19
- nautobot/extras/tables.py +52 -68
- nautobot/extras/templates/extras/approval_dashboard.html +7 -5
- nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
- nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/gitrepository_result.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -96
- nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
- nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
- nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
- nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
- nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
- nautobot/extras/templates/extras/inc/json_format.html +10 -3
- nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
- nautobot/extras/templates/extras/job.html +29 -12
- nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
- nautobot/extras/templates/extras/job_edit.html +52 -46
- nautobot/extras/templates/extras/job_list.html +29 -25
- nautobot/extras/templates/extras/marketplace.html +5 -9
- nautobot/extras/templates/extras/object_configcontext.html +1 -1
- nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
- nautobot/extras/templates/extras/objectchange_retrieve.html +19 -37
- nautobot/extras/templates/extras/plugin_detail.html +26 -21
- nautobot/extras/templates/extras/plugins_list.html +16 -26
- nautobot/extras/templates/extras/role_retrieve.html +64 -0
- nautobot/extras/templates/extras/scheduledjob.html +4 -2
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templatetags/custom_links.py +12 -12
- nautobot/extras/templatetags/job_buttons.py +14 -12
- nautobot/extras/test_jobs/invalid_import.py +9 -0
- nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
- nautobot/extras/test_jobs/missing_import.py +11 -0
- nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
- nautobot/extras/tests/integration/test_customfields.py +8 -7
- nautobot/extras/tests/integration/test_dynamicgroups.py +5 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
- nautobot/extras/tests/integration/test_plugins.py +18 -6
- nautobot/extras/tests/test_api.py +27 -18
- nautobot/extras/tests/test_approvals.py +38 -38
- nautobot/extras/tests/test_changelog.py +35 -3
- nautobot/extras/tests/test_customfields.py +22 -13
- nautobot/extras/tests/test_customfields_filters.py +479 -0
- nautobot/extras/tests/test_dynamicgroups.py +39 -1
- nautobot/extras/tests/test_filters.py +21 -19
- nautobot/extras/tests/test_forms.py +18 -21
- nautobot/extras/tests/test_jobs.py +25 -4
- nautobot/extras/tests/test_migrations.py +1 -0
- nautobot/extras/tests/test_models.py +13 -31
- nautobot/extras/tests/test_plugins.py +36 -10
- nautobot/extras/tests/test_views.py +31 -30
- nautobot/extras/views.py +81 -19
- nautobot/ipam/factory.py +7 -0
- nautobot/ipam/filter_mixins.py +38 -0
- nautobot/ipam/filters.py +27 -38
- nautobot/ipam/formfields.py +1 -1
- nautobot/ipam/forms.py +6 -3
- nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
- nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
- nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
- nautobot/ipam/models.py +29 -2
- nautobot/ipam/navigation.py +3 -2
- nautobot/ipam/signals.py +71 -0
- nautobot/ipam/tables.py +13 -6
- nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
- nautobot/ipam/templates/ipam/ipaddress.html +14 -0
- nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
- nautobot/ipam/templates/ipam/namespace_update.html +15 -0
- nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
- nautobot/ipam/templates/ipam/prefix_list.html +14 -13
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +1 -1
- nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
- nautobot/ipam/tests/migration/test_migrations.py +89 -0
- nautobot/ipam/tests/test_api.py +13 -6
- nautobot/ipam/tests/test_filters.py +10 -0
- nautobot/ipam/tests/test_forms.py +1 -1
- nautobot/ipam/tests/test_models.py +43 -1
- nautobot/ipam/tests/test_tables.py +1 -2
- nautobot/ipam/tests/test_utils.py +1 -1
- nautobot/ipam/tests/test_views.py +13 -14
- nautobot/ipam/ui.py +0 -17
- nautobot/ipam/utils/migrations.py +16 -2
- nautobot/ipam/utils/testing.py +9 -3
- nautobot/ipam/views.py +46 -6
- nautobot/project-static/dist/css/nautobot.css +1 -1
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/nautobot.js +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/js/cabletrace.js +1 -1
- nautobot/project-static/js/interface_filtering.js +20 -16
- nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud.svg +1 -1
- nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
- nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
- nautobot/project-static/nautobot-icons/elements.svg +1 -1
- nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
- nautobot/project-static/nautobot-icons/hammer.svg +1 -1
- nautobot/project-static/nautobot-icons/organization.svg +3 -0
- nautobot/project-static/nautobot-icons/secrets.svg +1 -1
- nautobot/project-static/nautobot-icons/security.svg +3 -0
- nautobot/project-static/nautobot-icons/server.svg +1 -1
- nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
- nautobot/project-static/nautobot-icons/star.svg +1 -1
- nautobot/tenancy/api/serializers.py +1 -0
- nautobot/tenancy/api/views.py +2 -1
- nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
- nautobot/tenancy/navigation.py +3 -1
- nautobot/tenancy/tests/test_filters.py +0 -2
- nautobot/tenancy/views.py +2 -1
- nautobot/ui/src/js/collapse.js +3 -3
- nautobot/ui/src/js/nautobot.js +16 -0
- nautobot/ui/src/scss/colors.scss +1 -1
- nautobot/ui/src/scss/nautobot.scss +61 -28
- nautobot/users/templates/users/profile.html +45 -12
- nautobot/users/templates/users/sessionkey_delete.html +1 -1
- nautobot/users/tests/test_api.py +4 -0
- nautobot/users/views.py +4 -2
- nautobot/virtualization/models.py +1 -68
- nautobot/virtualization/navigation.py +3 -2
- nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
- nautobot/virtualization/tests/test_api.py +3 -0
- nautobot/virtualization/tests/test_models.py +44 -4
- nautobot/vpn/__init__.py +0 -0
- nautobot/vpn/api/serializers.py +113 -0
- nautobot/vpn/api/urls.py +19 -0
- nautobot/vpn/api/views.py +70 -0
- nautobot/vpn/apps.py +8 -0
- nautobot/vpn/choices.py +171 -0
- nautobot/vpn/factory.py +209 -0
- nautobot/vpn/filters.py +233 -0
- nautobot/vpn/forms.py +486 -0
- nautobot/vpn/homepage.py +19 -0
- nautobot/vpn/migrations/0001_initial.py +541 -0
- nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
- nautobot/vpn/migrations/__init__.py +0 -0
- nautobot/vpn/models.py +527 -0
- nautobot/vpn/navigation.py +98 -0
- nautobot/vpn/tables.py +380 -0
- nautobot/vpn/templates/vpn/vpnprofile.html +2 -0
- nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
- nautobot/vpn/tests/__init__.py +0 -0
- nautobot/vpn/tests/test_api.py +341 -0
- nautobot/vpn/tests/test_filters.py +139 -0
- nautobot/vpn/tests/test_forms.py +294 -0
- nautobot/vpn/tests/test_models.py +97 -0
- nautobot/vpn/tests/test_views.py +281 -0
- nautobot/vpn/urls.py +16 -0
- nautobot/vpn/views.py +437 -0
- nautobot/wireless/navigation.py +3 -2
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
- nautobot/wireless/tests/test_api.py +1 -1
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +14 -14
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +417 -366
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
- nautobot/data_validation/template_content.py +0 -42
- nautobot/dcim/filters/mixins.py +0 -354
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
- /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
nautobot/extras/api/views.py
CHANGED
|
@@ -1093,7 +1093,15 @@ class JobButtonViewSet(NotesViewSetMixin, ModelViewSet):
|
|
|
1093
1093
|
#
|
|
1094
1094
|
|
|
1095
1095
|
|
|
1096
|
-
class ScheduledJobViewSet(
|
|
1096
|
+
class ScheduledJobViewSet(
|
|
1097
|
+
# DRF mixins:
|
|
1098
|
+
# note no CreateModelMixin or UpdateModelMixin
|
|
1099
|
+
mixins.DestroyModelMixin,
|
|
1100
|
+
# Nautobot mixins:
|
|
1101
|
+
BulkDestroyModelMixin,
|
|
1102
|
+
# Base class
|
|
1103
|
+
ReadOnlyModelViewSet,
|
|
1104
|
+
):
|
|
1097
1105
|
"""
|
|
1098
1106
|
Retrieve a list of scheduled jobs
|
|
1099
1107
|
"""
|
nautobot/extras/choices.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from celery import states
|
|
2
2
|
|
|
3
3
|
from nautobot.core.choices import ChoiceSet
|
|
4
|
-
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
5
4
|
|
|
6
5
|
#
|
|
7
6
|
# Approval Workflows
|
|
@@ -159,7 +158,7 @@ class CustomFieldTypeChoices(ChoiceSet):
|
|
|
159
158
|
|
|
160
159
|
|
|
161
160
|
class ButtonClassChoices(ChoiceSet):
|
|
162
|
-
CLASS_DEFAULT = "default"
|
|
161
|
+
CLASS_DEFAULT = "default" # maps to "secondary" in v3 UI, but kept for backwards compatibility
|
|
163
162
|
CLASS_PRIMARY = "primary"
|
|
164
163
|
CLASS_SUCCESS = "success"
|
|
165
164
|
CLASS_INFO = "info"
|
|
@@ -171,23 +170,13 @@ class ButtonClassChoices(ChoiceSet):
|
|
|
171
170
|
(CLASS_DEFAULT, "Default"),
|
|
172
171
|
(CLASS_PRIMARY, "Primary (blue)"),
|
|
173
172
|
(CLASS_SUCCESS, "Success (green)"),
|
|
174
|
-
(CLASS_INFO, "Info (
|
|
173
|
+
(CLASS_INFO, "Info (blue)"),
|
|
175
174
|
(CLASS_WARNING, "Warning (orange)"),
|
|
176
175
|
(CLASS_DANGER, "Danger (red)"),
|
|
177
176
|
(CLASS_LINK, "None (link)"),
|
|
178
177
|
)
|
|
179
178
|
|
|
180
179
|
|
|
181
|
-
#
|
|
182
|
-
# CustomLinks
|
|
183
|
-
#
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
@class_deprecated_in_favor_of(ButtonClassChoices)
|
|
187
|
-
class CustomLinkButtonClassChoices(ButtonClassChoices):
|
|
188
|
-
pass
|
|
189
|
-
|
|
190
|
-
|
|
191
180
|
#
|
|
192
181
|
# Dynamic Groups
|
|
193
182
|
#
|
|
@@ -21,7 +21,7 @@ from nautobot.extras.choices import (
|
|
|
21
21
|
CustomFieldTypeChoices,
|
|
22
22
|
RelationshipSideChoices,
|
|
23
23
|
)
|
|
24
|
-
from nautobot.extras.
|
|
24
|
+
from nautobot.extras.filter_mixins_customfields import (
|
|
25
25
|
CustomFieldBooleanFilter,
|
|
26
26
|
CustomFieldCharFilter,
|
|
27
27
|
CustomFieldDateFilter,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from functools import reduce
|
|
2
|
+
import operator
|
|
3
|
+
|
|
1
4
|
from django.db.models import Q
|
|
2
5
|
from django.forms import IntegerField
|
|
3
6
|
import django_filters
|
|
@@ -36,19 +39,52 @@ class CustomFieldFilterMixin:
|
|
|
36
39
|
super().__init__(*args, **kwargs)
|
|
37
40
|
self.field_name = f"_custom_field_data__{self.field_name}"
|
|
38
41
|
|
|
42
|
+
def generate_query(self, value):
|
|
43
|
+
# This method may be called from extras.models.DynamicGroup._generate_query_for_filter method
|
|
44
|
+
# to generate proper query for given field. But at this point, we don't know if the field will be negated or not
|
|
45
|
+
# That's why we're preparing query that works both: for positional filtering and negated one.
|
|
46
|
+
# For positional filtering, when we're expecting some value, the field must exists (key in custom field data JSONB)
|
|
47
|
+
# and value can't be None (null in db)
|
|
48
|
+
# For negated filtering we're expecting field without some value, but key may be missing or value can be None (null in db)
|
|
49
|
+
# Please refer to the filter method below, for more context.
|
|
50
|
+
if value == "null" or value == ["null"]:
|
|
51
|
+
return Q(**{f"{self.field_name}__exact": None}) & Q(**{f"{self.field_name}__isnull": False})
|
|
52
|
+
|
|
53
|
+
if isinstance(value, (list, tuple)):
|
|
54
|
+
value_match = reduce(operator.or_, [Q(**{f"{self.field_name}__{self.lookup_expr}": v}) for v in value])
|
|
55
|
+
else:
|
|
56
|
+
value_match = Q(**{f"{self.field_name}__{self.lookup_expr}": value})
|
|
57
|
+
value_is_not_none = ~Q(**{f"{self.field_name}__exact": None})
|
|
58
|
+
key_is_present_in_jsonb = Q(
|
|
59
|
+
**{f"{self.field_name}__isnull": False}
|
|
60
|
+
) # __isnull and __has_key has same output in case of JSONB fields
|
|
61
|
+
|
|
62
|
+
return value_match & value_is_not_none & key_is_present_in_jsonb
|
|
63
|
+
|
|
39
64
|
def filter(self, qs, value):
|
|
40
65
|
if value in django_filters.constants.EMPTY_VALUES:
|
|
41
66
|
return qs
|
|
42
67
|
|
|
43
|
-
if value == "null":
|
|
68
|
+
if value == "null" or value == ["null"]:
|
|
44
69
|
return self.get_method(qs)(
|
|
45
|
-
Q(**{f"{self.field_name}__exact": None})
|
|
70
|
+
Q(**{f"{self.field_name}__exact": None}) & Q(**{f"{self.field_name}__isnull": False})
|
|
46
71
|
)
|
|
47
72
|
|
|
48
73
|
# Custom fields require special handling for exclude filtering.
|
|
49
|
-
# Return custom fields that don't match the value
|
|
74
|
+
# Return custom fields that don't match the value, key is missing or value is set to null
|
|
75
|
+
# For JSONB fields, like `_custom_field_data`:
|
|
76
|
+
# __isnull and __has_key returns those records which has key
|
|
77
|
+
# __isnull is not checking the actual value in JSONB!
|
|
78
|
+
# to check for null value, we need to use exact
|
|
79
|
+
# With exclude filtering we need to take into account all cases:
|
|
80
|
+
# - no key - handled by __isnull check
|
|
81
|
+
# - key is present with null - handled by __exact=None
|
|
82
|
+
# - key is present with some value - handled by filter
|
|
83
|
+
# - key is present with empty str - handled by filter
|
|
50
84
|
if self.exclude:
|
|
51
|
-
qs_null_custom_fields = qs.filter(
|
|
85
|
+
qs_null_custom_fields = qs.filter(
|
|
86
|
+
Q(**{f"{self.field_name}__isnull": True}) | Q(**{f"{self.field_name}__exact": None})
|
|
87
|
+
).distinct()
|
|
52
88
|
return super().filter(qs, value).distinct() | qs_null_custom_fields
|
|
53
89
|
|
|
54
90
|
return super().filter(qs, value)
|
|
@@ -58,7 +94,7 @@ class CustomFieldBooleanFilter(CustomFieldFilterMixin, django_filters.BooleanFil
|
|
|
58
94
|
"""Custom field single value filter for backwards compatibility"""
|
|
59
95
|
|
|
60
96
|
|
|
61
|
-
class CustomFieldCharFilter(CustomFieldFilterMixin, django_filters.
|
|
97
|
+
class CustomFieldCharFilter(CustomFieldFilterMixin, django_filters.CharFilter):
|
|
62
98
|
"""Custom field single value filter for backwards compatibility"""
|
|
63
99
|
|
|
64
100
|
|
|
@@ -92,7 +128,7 @@ class CustomFieldMultiSelectFilter(CustomFieldSelectFilter):
|
|
|
92
128
|
super().__init__(*args, **kwargs)
|
|
93
129
|
|
|
94
130
|
|
|
95
|
-
class CustomFieldNumberFilter(CustomFieldFilterMixin, django_filters.
|
|
131
|
+
class CustomFieldNumberFilter(CustomFieldFilterMixin, django_filters.NumberFilter):
|
|
96
132
|
"""Custom field single value filter for backwards compatibility"""
|
|
97
133
|
|
|
98
134
|
field_class = IntegerField
|
|
@@ -23,7 +23,6 @@ from nautobot.core.filters import (
|
|
|
23
23
|
RelatedMembershipBooleanFilter,
|
|
24
24
|
SearchFilter,
|
|
25
25
|
)
|
|
26
|
-
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
27
26
|
from nautobot.dcim.models import DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
28
27
|
from nautobot.extras.choices import (
|
|
29
28
|
JobQueueTypeChoices,
|
|
@@ -33,7 +32,18 @@ from nautobot.extras.choices import (
|
|
|
33
32
|
SecretsGroupAccessTypeChoices,
|
|
34
33
|
SecretsGroupSecretTypeChoices,
|
|
35
34
|
)
|
|
36
|
-
from nautobot.extras.
|
|
35
|
+
from nautobot.extras.filter_mixins import (
|
|
36
|
+
ConfigContextRoleFilter,
|
|
37
|
+
CreatedUpdatedModelFilterSetMixin,
|
|
38
|
+
CustomFieldModelFilterSetMixin,
|
|
39
|
+
LocalContextModelFilterSetMixin,
|
|
40
|
+
RelationshipFilter,
|
|
41
|
+
RelationshipModelFilterSetMixin,
|
|
42
|
+
RoleModelFilterSetMixin,
|
|
43
|
+
StatusFilter,
|
|
44
|
+
StatusModelFilterSetMixin,
|
|
45
|
+
)
|
|
46
|
+
from nautobot.extras.filter_mixins_customfields import (
|
|
37
47
|
CustomFieldBooleanFilter,
|
|
38
48
|
CustomFieldCharFilter,
|
|
39
49
|
CustomFieldDateFilter,
|
|
@@ -45,17 +55,6 @@ from nautobot.extras.filters.customfields import (
|
|
|
45
55
|
CustomFieldMultiValueNumberFilter,
|
|
46
56
|
CustomFieldNumberFilter,
|
|
47
57
|
)
|
|
48
|
-
from nautobot.extras.filters.mixins import (
|
|
49
|
-
ConfigContextRoleFilter,
|
|
50
|
-
CreatedUpdatedModelFilterSetMixin,
|
|
51
|
-
CustomFieldModelFilterSetMixin,
|
|
52
|
-
LocalContextModelFilterSetMixin,
|
|
53
|
-
RelationshipFilter,
|
|
54
|
-
RelationshipModelFilterSetMixin,
|
|
55
|
-
RoleModelFilterSetMixin,
|
|
56
|
-
StatusFilter,
|
|
57
|
-
StatusModelFilterSetMixin,
|
|
58
|
-
)
|
|
59
58
|
from nautobot.extras.models import (
|
|
60
59
|
ApprovalWorkflow,
|
|
61
60
|
ApprovalWorkflowDefinition,
|
|
@@ -126,14 +125,12 @@ __all__ = (
|
|
|
126
125
|
"ContactFilterSet",
|
|
127
126
|
"ContentTypeFilterSet",
|
|
128
127
|
"ContentTypeMultipleChoiceFilter",
|
|
129
|
-
"CreatedUpdatedFilterSet",
|
|
130
128
|
"CreatedUpdatedModelFilterSetMixin",
|
|
131
129
|
"CustomFieldBooleanFilter",
|
|
132
130
|
"CustomFieldCharFilter",
|
|
133
131
|
"CustomFieldDateFilter",
|
|
134
132
|
"CustomFieldFilterMixin",
|
|
135
133
|
"CustomFieldJSONFilter",
|
|
136
|
-
"CustomFieldModelFilterSet",
|
|
137
134
|
"CustomFieldModelFilterSetMixin",
|
|
138
135
|
"CustomFieldMultiSelectFilter",
|
|
139
136
|
"CustomFieldMultiValueCharFilter",
|
|
@@ -153,7 +150,6 @@ __all__ = (
|
|
|
153
150
|
"JobQueueAssignmentFilterSet",
|
|
154
151
|
"JobQueueFilterSet",
|
|
155
152
|
"JobResultFilterSet",
|
|
156
|
-
"LocalContextFilterSet",
|
|
157
153
|
"LocalContextModelFilterSetMixin",
|
|
158
154
|
"MetadataChoiceFilterSet",
|
|
159
155
|
"MetadataTypeFilterSet",
|
|
@@ -178,17 +174,6 @@ __all__ = (
|
|
|
178
174
|
)
|
|
179
175
|
|
|
180
176
|
|
|
181
|
-
# TODO: remove in 2.2
|
|
182
|
-
@class_deprecated_in_favor_of(CreatedUpdatedModelFilterSetMixin)
|
|
183
|
-
class CreatedUpdatedFilterSet(CreatedUpdatedModelFilterSetMixin):
|
|
184
|
-
pass
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
@class_deprecated_in_favor_of(RelationshipModelFilterSetMixin)
|
|
188
|
-
class RelationshipModelFilterSet(RelationshipModelFilterSetMixin):
|
|
189
|
-
pass
|
|
190
|
-
|
|
191
|
-
|
|
192
177
|
#
|
|
193
178
|
# Approval Workflows
|
|
194
179
|
#
|
|
@@ -199,7 +184,7 @@ class ApprovalWorkflowStageDefinitionFilterSet(BaseFilterSet):
|
|
|
199
184
|
|
|
200
185
|
q = SearchFilter(
|
|
201
186
|
filter_predicates={
|
|
202
|
-
"
|
|
187
|
+
"sequence": {
|
|
203
188
|
"lookup_expr": "exact",
|
|
204
189
|
"preprocessor": int,
|
|
205
190
|
},
|
|
@@ -572,12 +557,6 @@ class ContentTypeFilterSet(BaseFilterSet):
|
|
|
572
557
|
return queryset.filter(FeatureQuery(value).get_query())
|
|
573
558
|
|
|
574
559
|
|
|
575
|
-
# TODO: remove in 2.2
|
|
576
|
-
@class_deprecated_in_favor_of(CustomFieldModelFilterSetMixin)
|
|
577
|
-
class CustomFieldModelFilterSet(CustomFieldModelFilterSetMixin):
|
|
578
|
-
pass
|
|
579
|
-
|
|
580
|
-
|
|
581
560
|
class CustomFieldFilterSet(BaseFilterSet):
|
|
582
561
|
q = SearchFilter(
|
|
583
562
|
filter_predicates={
|
|
@@ -787,7 +766,7 @@ class CustomLinkFilterSet(BaseFilterSet):
|
|
|
787
766
|
#
|
|
788
767
|
|
|
789
768
|
# Must be imported **after* NautobotFilterSet class is defined to avoid a circular import loop.
|
|
790
|
-
from nautobot.tenancy.
|
|
769
|
+
from nautobot.tenancy.filter_mixins import TenancyModelFilterSetMixin # noqa: E402
|
|
791
770
|
|
|
792
771
|
|
|
793
772
|
class DynamicGroupFilterSet(TenancyModelFilterSetMixin, NautobotFilterSet):
|
|
@@ -1270,17 +1249,6 @@ class JobButtonFilterSet(BaseFilterSet):
|
|
|
1270
1249
|
)
|
|
1271
1250
|
|
|
1272
1251
|
|
|
1273
|
-
#
|
|
1274
|
-
# Filter for Local Config Context Data
|
|
1275
|
-
#
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
# TODO: remove in 2.2
|
|
1279
|
-
@class_deprecated_in_favor_of(LocalContextModelFilterSetMixin)
|
|
1280
|
-
class LocalContextFilterSet(LocalContextModelFilterSetMixin):
|
|
1281
|
-
pass
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
1252
|
#
|
|
1285
1253
|
# Metadata
|
|
1286
1254
|
#
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -42,7 +42,6 @@ from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
|
|
|
42
42
|
from nautobot.core.forms.fields import MultiValueCharField
|
|
43
43
|
from nautobot.core.forms.forms import ConfirmationForm
|
|
44
44
|
from nautobot.core.forms.widgets import ClearableFileInput
|
|
45
|
-
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
46
45
|
from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
47
46
|
from nautobot.extras.choices import (
|
|
48
47
|
ApprovalWorkflowStateChoices,
|
|
@@ -153,7 +152,6 @@ __all__ = (
|
|
|
153
152
|
"ConfigContextSchemaBulkEditForm",
|
|
154
153
|
"ConfigContextSchemaFilterForm",
|
|
155
154
|
"ConfigContextSchemaForm",
|
|
156
|
-
"CustomFieldBulkCreateForm", # 2.0 TODO remove this deprecated class
|
|
157
155
|
"CustomFieldBulkDeleteForm",
|
|
158
156
|
"CustomFieldBulkEditForm",
|
|
159
157
|
"CustomFieldChoiceFormSet",
|
|
@@ -338,7 +336,7 @@ ApprovalWorkflowStageDefinitionFormSet = inlineformset_factory(
|
|
|
338
336
|
extra=5,
|
|
339
337
|
widgets={
|
|
340
338
|
"name": forms.TextInput(attrs={"class": "form-control"}),
|
|
341
|
-
"
|
|
339
|
+
"sequence": forms.NumberInput(attrs={"class": "form-control"}),
|
|
342
340
|
"min_approvers": forms.NumberInput(attrs={"class": "form-control"}),
|
|
343
341
|
"denial_message": forms.TextInput(attrs={"class": "form-control"}),
|
|
344
342
|
"approver_group": forms.Select(attrs={"class": "form-control"}),
|
|
@@ -352,8 +350,8 @@ class ApprovalWorkflowStageDefinitionBulkEditForm(TagsBulkEditFormMixin, Nautobo
|
|
|
352
350
|
pk = forms.ModelMultipleChoiceField(
|
|
353
351
|
queryset=ApprovalWorkflowStageDefinition.objects.all(), widget=forms.MultipleHiddenInput
|
|
354
352
|
)
|
|
355
|
-
|
|
356
|
-
min_approvers = forms.IntegerField(required=False, label="
|
|
353
|
+
sequence = forms.IntegerField(required=False, label="Sequence")
|
|
354
|
+
min_approvers = forms.IntegerField(required=False, label="Minimum Approvers")
|
|
357
355
|
denial_message = forms.CharField(required=False, label="Denial Message")
|
|
358
356
|
|
|
359
357
|
class Meta:
|
|
@@ -374,8 +372,8 @@ class ApprovalWorkflowStageDefinitionFilterForm(NautobotFilterForm):
|
|
|
374
372
|
required=False,
|
|
375
373
|
label="Approval Workflow Definition",
|
|
376
374
|
)
|
|
377
|
-
|
|
378
|
-
min_approvers = forms.IntegerField(required=False, label="
|
|
375
|
+
sequence = forms.IntegerField(required=False, label="Sequence")
|
|
376
|
+
min_approvers = forms.IntegerField(required=False, label="Minimum Approvers")
|
|
379
377
|
approver_group = DynamicModelChoiceField(
|
|
380
378
|
queryset=Group.objects.all(),
|
|
381
379
|
required=False,
|
|
@@ -827,12 +825,6 @@ class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelFormMixin):
|
|
|
827
825
|
self.custom_fields.append(field_name)
|
|
828
826
|
|
|
829
827
|
|
|
830
|
-
# 2.0 TODO: remove this class
|
|
831
|
-
@class_deprecated_in_favor_of(CustomFieldModelBulkEditFormMixin)
|
|
832
|
-
class CustomFieldBulkCreateForm(CustomFieldModelBulkEditFormMixin):
|
|
833
|
-
"""No longer needed as a separate class - use CustomFieldModelBulkEditFormMixin instead."""
|
|
834
|
-
|
|
835
|
-
|
|
836
828
|
class CustomFieldBulkDeleteForm(ConfirmationForm):
|
|
837
829
|
def __init__(self, *args, delete_all=False, **kwargs):
|
|
838
830
|
super().__init__(*args, **kwargs)
|
nautobot/extras/forms/mixins.py
CHANGED
|
@@ -11,7 +11,6 @@ from nautobot.core.forms import (
|
|
|
11
11
|
DynamicModelChoiceField,
|
|
12
12
|
DynamicModelMultipleChoiceField,
|
|
13
13
|
)
|
|
14
|
-
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
15
14
|
from nautobot.extras.choices import (
|
|
16
15
|
DynamicGroupTypeChoices,
|
|
17
16
|
RelationshipSideChoices,
|
|
@@ -48,17 +47,10 @@ __all__ = ( # noqa:RUF022
|
|
|
48
47
|
"StatusModelBulkEditFormMixin",
|
|
49
48
|
"StatusModelFilterFormMixin",
|
|
50
49
|
"TagsBulkEditFormMixin",
|
|
51
|
-
# 2.0 TODO: remove the below deprecated aliases
|
|
52
|
-
"AddRemoveTagsForm",
|
|
53
|
-
"CustomFieldBulkEditForm",
|
|
54
|
-
"CustomFieldModelForm",
|
|
55
|
-
"RelationshipModelForm",
|
|
56
50
|
"RoleModelBulkEditFormMixin",
|
|
57
51
|
"RoleModelFilterFormMixin",
|
|
58
52
|
"RoleNotRequiredModelFormMixin",
|
|
59
53
|
"RoleRequiredModelFormMixin",
|
|
60
|
-
"StatusBulkEditFormMixin",
|
|
61
|
-
"StatusFilterFormMixin",
|
|
62
54
|
)
|
|
63
55
|
|
|
64
56
|
|
|
@@ -854,36 +846,3 @@ class TagsBulkEditFormMixin(BulkEditForm):
|
|
|
854
846
|
query_params={"content_types": self.model._meta.label_lower},
|
|
855
847
|
required=False,
|
|
856
848
|
)
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
# 2.2 TODO: Names below are only for backward compatibility with Nautobot 1.3 and earlier. Remove in 2.2
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
@class_deprecated_in_favor_of(TagsBulkEditFormMixin)
|
|
863
|
-
class AddRemoveTagsForm(TagsBulkEditFormMixin):
|
|
864
|
-
pass
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
@class_deprecated_in_favor_of(CustomFieldModelBulkEditFormMixin)
|
|
868
|
-
class CustomFieldBulkEditForm(CustomFieldModelBulkEditFormMixin):
|
|
869
|
-
pass
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
@class_deprecated_in_favor_of(CustomFieldModelFormMixin)
|
|
873
|
-
class CustomFieldModelForm(CustomFieldModelFormMixin):
|
|
874
|
-
pass
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
@class_deprecated_in_favor_of(RelationshipModelFormMixin)
|
|
878
|
-
class RelationshipModelForm(RelationshipModelFormMixin):
|
|
879
|
-
pass
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
@class_deprecated_in_favor_of(StatusModelBulkEditFormMixin)
|
|
883
|
-
class StatusBulkEditFormMixin(StatusModelBulkEditFormMixin):
|
|
884
|
-
pass
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
@class_deprecated_in_favor_of(StatusModelFilterFormMixin)
|
|
888
|
-
class StatusFilterFormMixin(StatusModelFilterFormMixin):
|
|
889
|
-
pass
|
|
@@ -11,6 +11,7 @@ from nautobot.dcim import choices as dcim_choices
|
|
|
11
11
|
from nautobot.extras import choices as extras_choices
|
|
12
12
|
from nautobot.ipam import choices as ipam_choices
|
|
13
13
|
from nautobot.virtualization import choices as vm_choices
|
|
14
|
+
from nautobot.vpn import choices as vpn_choices
|
|
14
15
|
|
|
15
16
|
# List of 2-tuples of (model_path, choiceset)
|
|
16
17
|
# Add new mappings here as other models are supported.
|
|
@@ -36,6 +37,7 @@ STATUS_CHOICESET_MAP = {
|
|
|
36
37
|
"ipam.VRF": ipam_choices.VRFStatusChoices,
|
|
37
38
|
"virtualization.VirtualMachine": vm_choices.VirtualMachineStatusChoices,
|
|
38
39
|
"virtualization.VMInterface": vm_choices.VMInterfaceStatusChoices,
|
|
40
|
+
"vpn.VPNTunnel": vpn_choices.VPNTunnelStatusChoices,
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
|
|
@@ -101,6 +103,7 @@ STATUS_DESCRIPTION_MAP = {
|
|
|
101
103
|
# Add new mappings here as other models are supported.
|
|
102
104
|
ROLE_CHOICESET_MAP = {
|
|
103
105
|
"extras.ContactAssociation": extras_choices.ContactAssociationRoleChoices,
|
|
106
|
+
"vpn.VPNTunnelEndpoint": vpn_choices.VPNTunnelEndpointRoleChoices,
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
# Map of role name -> default hex_color used when importing color choices in `export_roles_from_choiceset()`.
|
|
@@ -110,6 +113,9 @@ ROLE_COLOR_MAP = {
|
|
|
110
113
|
"Billing": ColorChoices.COLOR_GREEN,
|
|
111
114
|
"Support": ColorChoices.COLOR_YELLOW,
|
|
112
115
|
"On Site": ColorChoices.COLOR_BLACK,
|
|
116
|
+
"Hub": ColorChoices.COLOR_DARK_GREEN,
|
|
117
|
+
"Spoke": ColorChoices.COLOR_LIGHT_GREEN,
|
|
118
|
+
"Peer": ColorChoices.COLOR_ORANGE,
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
# Map of role name -> description used when importing role choices in `export_roles_from_choiceset()`.
|
|
@@ -118,6 +124,9 @@ ROLE_DESCRIPTION_MAP = {
|
|
|
118
124
|
"Billing": "Unit plays a billing role",
|
|
119
125
|
"Support": "Unit plays a support role",
|
|
120
126
|
"On Site": "Unit plays an on site role",
|
|
127
|
+
"Hub": "Unit plays a Hub role",
|
|
128
|
+
"Spoke": "Unit plays a Spoke role",
|
|
129
|
+
"Peer": "Unit plays a Peer role",
|
|
121
130
|
}
|
|
122
131
|
|
|
123
132
|
|
|
@@ -68,7 +68,7 @@ class Migration(migrations.Migration):
|
|
|
68
68
|
),
|
|
69
69
|
("name", models.CharField(max_length=255, unique=True)),
|
|
70
70
|
("model_constraints", models.JSONField(blank=True, default=dict)),
|
|
71
|
-
("
|
|
71
|
+
("weight", models.IntegerField(default=0)),
|
|
72
72
|
(
|
|
73
73
|
"model_content_type",
|
|
74
74
|
models.ForeignKey(
|
|
@@ -83,7 +83,7 @@ class Migration(migrations.Migration):
|
|
|
83
83
|
options={
|
|
84
84
|
"verbose_name": "Approval Workflow Definition",
|
|
85
85
|
"ordering": ["name"],
|
|
86
|
-
"unique_together": {("model_content_type", "
|
|
86
|
+
"unique_together": {("model_content_type", "weight")},
|
|
87
87
|
},
|
|
88
88
|
bases=(
|
|
89
89
|
nautobot.extras.models.mixins.DynamicGroupMixin,
|
|
@@ -122,7 +122,7 @@ class Migration(migrations.Migration):
|
|
|
122
122
|
],
|
|
123
123
|
options={
|
|
124
124
|
"verbose_name": "Approval Workflow Stage",
|
|
125
|
-
"ordering": ["approval_workflow", "
|
|
125
|
+
"ordering": ["approval_workflow", "approval_workflow_stage_definition__sequence"],
|
|
126
126
|
},
|
|
127
127
|
bases=(
|
|
128
128
|
nautobot.extras.models.mixins.DynamicGroupMixin,
|
|
@@ -179,7 +179,7 @@ class Migration(migrations.Migration):
|
|
|
179
179
|
"_custom_field_data",
|
|
180
180
|
models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
|
|
181
181
|
),
|
|
182
|
-
("
|
|
182
|
+
("sequence", models.PositiveIntegerField()),
|
|
183
183
|
("name", models.CharField(max_length=255)),
|
|
184
184
|
("min_approvers", models.PositiveIntegerField()),
|
|
185
185
|
("denial_message", models.CharField(blank=True, max_length=255)),
|
|
@@ -202,10 +202,10 @@ class Migration(migrations.Migration):
|
|
|
202
202
|
],
|
|
203
203
|
options={
|
|
204
204
|
"verbose_name": "Approval Workflow Stage Definition",
|
|
205
|
-
"ordering": ["approval_workflow_definition", "
|
|
205
|
+
"ordering": ["approval_workflow_definition", "sequence"],
|
|
206
206
|
"unique_together": {
|
|
207
207
|
("approval_workflow_definition", "name"),
|
|
208
|
-
("approval_workflow_definition", "
|
|
208
|
+
("approval_workflow_definition", "sequence"),
|
|
209
209
|
},
|
|
210
210
|
},
|
|
211
211
|
bases=(
|
nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Generated by Django 4.2.24 on 2025-10-04 00:03
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("extras", "0128_remove_job_approval_required_and_more"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="jobresult",
|
|
14
|
+
name="debug_log_count",
|
|
15
|
+
field=models.PositiveIntegerField(blank=True, editable=False, null=True),
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name="jobresult",
|
|
19
|
+
name="error_log_count",
|
|
20
|
+
field=models.PositiveIntegerField(blank=True, editable=False, null=True),
|
|
21
|
+
),
|
|
22
|
+
migrations.AddField(
|
|
23
|
+
model_name="jobresult",
|
|
24
|
+
name="info_log_count",
|
|
25
|
+
field=models.PositiveIntegerField(blank=True, editable=False, null=True),
|
|
26
|
+
),
|
|
27
|
+
migrations.AddField(
|
|
28
|
+
model_name="jobresult",
|
|
29
|
+
name="success_log_count",
|
|
30
|
+
field=models.PositiveIntegerField(blank=True, editable=False, null=True),
|
|
31
|
+
),
|
|
32
|
+
migrations.AddField(
|
|
33
|
+
model_name="jobresult",
|
|
34
|
+
name="warning_log_count",
|
|
35
|
+
field=models.PositiveIntegerField(blank=True, editable=False, null=True),
|
|
36
|
+
),
|
|
37
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Migration to populate job_results.*_log_counts on existing JobResults."""
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
from django.db.models import Count, Q
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _populate_log_counts(apps, *_):
|
|
8
|
+
JobResult = apps.get_model("extras", "JobResult")
|
|
9
|
+
job_results_missing_counts = JobResult.objects.filter(
|
|
10
|
+
Q(debug_log_count=None)
|
|
11
|
+
| Q(success_log_count=None)
|
|
12
|
+
| Q(info_log_count=None)
|
|
13
|
+
| Q(warning_log_count=None)
|
|
14
|
+
| Q(error_log_count=None)
|
|
15
|
+
)
|
|
16
|
+
for job_result in job_results_missing_counts:
|
|
17
|
+
db_log_counts = job_result.job_log_entries.aggregate(
|
|
18
|
+
debug_log_count=Count("pk", filter=Q(log_level="debug")),
|
|
19
|
+
success_log_count=Count("pk", filter=Q(log_level="success")),
|
|
20
|
+
info_log_count=Count("pk", filter=Q(log_level="info")),
|
|
21
|
+
warning_log_count=Count("pk", filter=Q(log_level="warning")),
|
|
22
|
+
error_log_count=Count(
|
|
23
|
+
"pk",
|
|
24
|
+
filter=Q(log_level__in=["failure", "error", "critical"]),
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
job_result.debug_log_count = db_log_counts["debug_log_count"]
|
|
28
|
+
job_result.success_log_count = db_log_counts["success_log_count"]
|
|
29
|
+
job_result.info_log_count = db_log_counts["info_log_count"]
|
|
30
|
+
job_result.warning_log_count = db_log_counts["warning_log_count"]
|
|
31
|
+
job_result.error_log_count = db_log_counts["error_log_count"]
|
|
32
|
+
job_result.save()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Migration(migrations.Migration):
|
|
36
|
+
dependencies = [
|
|
37
|
+
("extras", "0129_jobresult_debug_log_count_jobresult_error_log_count_and_more"),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
operations = [
|
|
41
|
+
migrations.RunPython(code=_populate_log_counts, reverse_code=migrations.RunPython.noop),
|
|
42
|
+
]
|
|
@@ -43,7 +43,7 @@ from .models import (
|
|
|
43
43
|
from .relationships import Relationship, RelationshipAssociation, RelationshipModel
|
|
44
44
|
from .roles import Role, RoleField
|
|
45
45
|
from .secrets import Secret, SecretsGroup, SecretsGroupAssociation
|
|
46
|
-
from .statuses import Status, StatusField
|
|
46
|
+
from .statuses import Status, StatusField
|
|
47
47
|
from .tags import Tag, TaggedItem
|
|
48
48
|
|
|
49
49
|
__all__ = (
|
|
@@ -103,7 +103,6 @@ __all__ = (
|
|
|
103
103
|
"StaticGroupAssociation",
|
|
104
104
|
"Status",
|
|
105
105
|
"StatusField",
|
|
106
|
-
"StatusModel",
|
|
107
106
|
"Tag",
|
|
108
107
|
"TaggedItem",
|
|
109
108
|
"Team",
|