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
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
{% if object.last_updated %}
|
|
3
3
|
<small class="align-items-center d-inline-flex gap-4 text-secondary">
|
|
4
4
|
{% if object.created %}
|
|
5
|
-
<span
|
|
6
|
-
|
|
5
|
+
<span data-bs-toggle="tooltip" title="Created at">
|
|
6
|
+
<span class="mdi mdi-bookmark-plus"></span> {{ object.created }}
|
|
7
|
+
<span class="vr mx-4"></span>
|
|
8
|
+
</span>
|
|
7
9
|
{% endif %}
|
|
8
|
-
<span
|
|
10
|
+
<span data-bs-toggle="tooltip" title="Last updated">
|
|
11
|
+
<span class="mdi mdi-clock"></span> {{ object.last_updated|timesince }} ago
|
|
12
|
+
</span>
|
|
9
13
|
</small>
|
|
10
14
|
{% endif %}
|
|
11
15
|
</p>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
{% firstof request.user.get_full_name request.user.username %}
|
|
61
61
|
</button>
|
|
62
62
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
63
|
-
<li><a class="dropdown-item" href="{% url 'about' %}"><span class="mdi mdi-information"></span>About</a></li>
|
|
63
|
+
<li><a class="dropdown-item" href="{% url 'about' %}"><span class="mdi mdi-information"></span>About Nautobot</a></li>
|
|
64
64
|
<li><a class="dropdown-item" href="{% url 'user:profile' %}"><span class="mdi mdi-account-box"></span>Profile</a></li>
|
|
65
65
|
<li><a class="dropdown-item" href="{% url 'extras:approver_dashboard' %}"><span class="mdi mdi-check-bold"></span>Approval Dashboard</a></li>
|
|
66
66
|
{% if request.user.is_staff %}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
{% comment %}3.0 TODO: Potentially remove this template pending no other references to it.{% endcomment %}
|
|
1
2
|
{% if images %}
|
|
2
3
|
<table class="table table-hover card-body">
|
|
3
4
|
<tr>
|
|
@@ -33,4 +34,4 @@
|
|
|
33
34
|
<div class="card-body">
|
|
34
35
|
<span class="text-secondary">None</span>
|
|
35
36
|
</div>
|
|
36
|
-
{% endif %}
|
|
37
|
+
{% endif %}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
aria-expanded="{% if cookie_sidenav_collapsed == 'true' %}false{% else %}true{% endif %}"
|
|
11
11
|
aria-label="Collapse sidenav"
|
|
12
12
|
class="bg-warning btn btm-sm btn-warning overflow-hidden p-4 position-absolute nb-sidenav-toggler"
|
|
13
|
+
data-bs-theme="dark"
|
|
13
14
|
type="button"
|
|
14
15
|
></button>
|
|
15
16
|
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
<img src="{% custom_branding_or_static 'logo' 'img/nautobot_logo.svg' %}"/>
|
|
21
22
|
</a>
|
|
22
23
|
|
|
23
|
-
<ul class="list-unstyled my-0 overflow-auto pt-10 w-100">
|
|
24
|
+
<ul class="list-unstyled my-0 overflow-x-hidden overflow-y-auto pt-10 w-100">
|
|
24
25
|
{% if request.user.is_authenticated %}
|
|
25
26
|
{% if nav_menu_version_control %}
|
|
26
27
|
<li>
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
{% endfor %}
|
|
22
22
|
</div>
|
|
23
23
|
<div class="justify-content-between mb-n20 nb-form-sticky-footer">
|
|
24
|
-
<button type="reset" class="btn btn-secondary">
|
|
25
|
-
<span aria-hidden="true" class="mdi mdi-close me-4"></span><!--
|
|
26
|
-
-->Clear All
|
|
27
|
-
</button>
|
|
28
24
|
<button type="submit" class="btn btn-primary">
|
|
29
25
|
<span class="mdi mdi-check me-4" aria-hidden="true"></span><!--
|
|
30
26
|
-->Apply Specified
|
|
31
27
|
</button>
|
|
28
|
+
<button type="reset" class="btn btn-secondary">
|
|
29
|
+
<span aria-hidden="true" class="mdi mdi-close me-4"></span><!--
|
|
30
|
+
-->Clear All
|
|
31
|
+
</button>
|
|
32
32
|
</div>
|
|
33
33
|
</form>
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
{% load helpers %}
|
|
3
3
|
{% load form_helpers %}
|
|
4
4
|
|
|
5
|
+
{% block title %}Home{% endblock title %}
|
|
6
|
+
|
|
5
7
|
{% block content %}
|
|
6
|
-
<div class="row" style="margin-block-start: {% if 'BANNER_LOGIN'|settings_or_config %}6.25{% else %}9.375{% endif %}rem;">
|
|
7
|
-
<div class="col-
|
|
8
|
+
<div class="row justify-content-center" style="margin-block-start: {% if 'BANNER_LOGIN'|settings_or_config %}6.25{% else %}9.375{% endif %}rem;">
|
|
9
|
+
<div class="col-sm-12 col-md-9 col-lg-7 nb-lg-max-width">
|
|
8
10
|
{% if "BANNER_LOGIN"|settings_or_config %}
|
|
9
11
|
<div class="alert alert-info text-center" role="alert">
|
|
10
12
|
{{ "BANNER_LOGIN"|settings_or_config|render_markdown }}
|
|
@@ -358,11 +358,12 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
358
358
|
# DEPLOYMENT_ID = os.environ["NAUTOBOT_DEPLOYMENT_ID"]
|
|
359
359
|
|
|
360
360
|
# Device names are not guaranteed globally-unique by Nautobot but in practice they often are.
|
|
361
|
-
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
361
|
+
# Select how Devices are uniquely identified:
|
|
362
|
+
# - 'location_tenant_name': combination of Location + Tenant + Name
|
|
363
|
+
# - 'name': Device name must be globally unique
|
|
364
|
+
# - 'none': No enforced uniqueness (rely on other validation rules or custom validators)
|
|
365
|
+
# if "NAUTOBOT_DEVICE_UNIQUENESS" in os.environ and os.environ["NAUTOBOT_DEVICE_UNIQUENESS"] != "":
|
|
366
|
+
# DEVICE_UNIQUENESS = os.environ["NAUTOBOT_DEVICE_UNIQUENESS"]
|
|
366
367
|
|
|
367
368
|
# Event Brokers
|
|
368
369
|
# EVENT_BROKERS = {}
|
|
@@ -51,6 +51,13 @@
|
|
|
51
51
|
|
|
52
52
|
{# Redoc doesn't change outer page styles. #}
|
|
53
53
|
body { margin: 0; padding: 0; }
|
|
54
|
+
|
|
55
|
+
[data-bs-theme="dark"] .redoc-wrap,
|
|
56
|
+
[data-bs-theme="dark"] .redoc-wrap > :last-child,
|
|
57
|
+
[data-bs-theme="dark"] .redoc-wrap .api-content > [data-section-id] > [data-section-id] > :last-child,
|
|
58
|
+
[data-bs-theme="dark"] .redoc-wrap .menu-content .operation-type {
|
|
59
|
+
filter: hue-rotate(180deg) invert(1);
|
|
60
|
+
}
|
|
54
61
|
</style>
|
|
55
62
|
{% endblock extra_styles %}
|
|
56
63
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
{% for obj_type in results %}
|
|
33
33
|
<a href="#{{ obj_type.name|lower }}" class="list-group-item">
|
|
34
34
|
{{ obj_type.name|bettertitle }}
|
|
35
|
-
<span class="badge">{{ obj_type.table.page.paginator.count }}</span>
|
|
35
|
+
<span class="badge bg-primary">{{ obj_type.table.page.paginator.count }}</span>
|
|
36
36
|
</a>
|
|
37
37
|
{% endfor %}
|
|
38
38
|
</div>
|
|
@@ -7,13 +7,27 @@
|
|
|
7
7
|
{% block extra_styles %}
|
|
8
8
|
<link rel="stylesheet" href="{% static 'drf_spectacular_sidecar/swagger-ui-dist/swagger-ui.css' %}">
|
|
9
9
|
<style>
|
|
10
|
-
|
|
10
|
+
/* Manual styling inherited from drf-spectacular */
|
|
11
11
|
html { box-sizing: border-box; overflow-y: scroll; }
|
|
12
12
|
*, *:after, *:before { box-sizing: inherit; }
|
|
13
|
-
body { background:
|
|
14
|
-
|
|
13
|
+
body { background: var(--bs-body-bg); margin: 0; }
|
|
14
|
+
/* Style overrides to address conflicts between Swagger styling and Nautobot/Bootstrap styling */
|
|
15
15
|
pre.version { border: none; background: none; }
|
|
16
16
|
.loading-container .loading { display: block; }
|
|
17
|
+
/* Dark theme support */
|
|
18
|
+
[data-bs-theme="dark"] .swagger-ui,
|
|
19
|
+
[data-bs-theme="dark"] .swagger-ui .backdrop-ux,
|
|
20
|
+
[data-bs-theme="dark"] .swagger-ui .microlight,
|
|
21
|
+
[data-bs-theme="dark"] .swagger-ui .opblock .opblock-summary-method {
|
|
22
|
+
filter: hue-rotate(180deg) invert(1);
|
|
23
|
+
}
|
|
24
|
+
[data-bs-theme="dark"] .swagger-ui input:is([type="email"], [type="file"], [type="password"], [type="search"], [type="text"]),
|
|
25
|
+
[data-bs-theme="dark"] .swagger-ui textarea {
|
|
26
|
+
color: var(--bs-body-bg);
|
|
27
|
+
}
|
|
28
|
+
[data-bs-theme="dark"] .swagger-ui .scheme-container {
|
|
29
|
+
background: transparent;
|
|
30
|
+
}
|
|
17
31
|
</style>
|
|
18
32
|
{% endblock extra_styles %}
|
|
19
33
|
|
|
@@ -164,10 +164,9 @@
|
|
|
164
164
|
<div class="modal-dialog" role="document">
|
|
165
165
|
<div class="modal-content">
|
|
166
166
|
<div class="modal-header">
|
|
167
|
+
<h4 class="modal-title">${field.name} Choices</h4>
|
|
167
168
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
|
|
168
|
-
<span aria-hidden="true">×</span>
|
|
169
169
|
</button>
|
|
170
|
-
<h4 class="modal-title"><code>${field.name}</code> Choices</h4>
|
|
171
170
|
</div>
|
|
172
171
|
<table class="table table-hover modal-body">
|
|
173
172
|
<tr><th>Import Value</th><th>Label</th></tr>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
{% block content %}
|
|
5
5
|
<div class="row">
|
|
6
|
-
<div class="col-md-6 mx-auto">
|
|
6
|
+
<div class="col-md-8 col-lg-6 mx-auto nb-lg-max-width">
|
|
7
7
|
<form action="" method="post">
|
|
8
8
|
{% csrf_token %}
|
|
9
9
|
{% for field in form.hidden_fields %}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
{% block title %}{% endblock %}
|
|
15
15
|
</div>
|
|
16
16
|
<div class="card-body">
|
|
17
|
-
{% block message %}<p>Are you sure?</p>{% endblock %}
|
|
17
|
+
<div class="mb-16">{% block message %}<p>Are you sure?</p>{% endblock %}</div>
|
|
18
18
|
<div class="gap-8 hstack justify-content-end">
|
|
19
19
|
<button type="submit" name="_confirm" class="btn btn-{{ button_class|default:'danger' }}">
|
|
20
20
|
<span aria-hidden="true" class="mdi mdi-check me-4"></span><!--
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
<div class="hstack gap-8">
|
|
16
16
|
{% if bulk_edit_url and permissions.change %}
|
|
17
|
-
<button type="submit"
|
|
17
|
+
<button type="submit"
|
|
18
|
+
name="_edit"
|
|
19
|
+
formaction="{% url bulk_edit_url %}{% if bulk_querystring %}?{{ bulk_querystring }}{% elif request.GET %}?{{ request.GET.urlencode }}{% endif %}"
|
|
20
|
+
class="btn btn-warning btn-sm"
|
|
21
|
+
disabled>
|
|
18
22
|
<span class="mdi mdi-pencil me-4" aria-hidden="true"></span>Edit All
|
|
19
23
|
</button>
|
|
20
24
|
{% endif %}
|
|
21
25
|
{% if bulk_delete_url and permissions.delete %}
|
|
22
|
-
<button type="submit"
|
|
26
|
+
<button type="submit"
|
|
27
|
+
name="_delete"
|
|
28
|
+
formaction="{% url bulk_delete_url %}{% if bulk_querystring %}?{{ bulk_querystring }}{% elif request.GET %}?{{ request.GET.urlencode }}{% endif %}"
|
|
29
|
+
class="btn btn-danger btn-sm"
|
|
30
|
+
disabled>
|
|
23
31
|
<span class="mdi mdi-trash-can-outline me-4" aria-hidden="true"></span>Delete All
|
|
24
32
|
</button>
|
|
25
33
|
{% endif %}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{% load form_helpers %}
|
|
2
2
|
|
|
3
|
-
<div class="mb-10 d-flex justify-content-center{% if field.errors %} has-error{% endif %}">
|
|
3
|
+
<div class="mb-10 d-md-flex justify-content-center{% if field.errors %} has-error{% endif %}">
|
|
4
4
|
{% if field|widget_type == 'checkboxinput' %}
|
|
5
5
|
<div class="col-md-9 offset-md-3">
|
|
6
6
|
<div class="form-check mt-6{% if field.errors %} has-error{% endif %}">
|
|
7
7
|
{{ field }}
|
|
8
8
|
<label class="form-check-label" for="{{ field.id_for_label }}">
|
|
9
9
|
{{ field.label }}
|
|
10
|
-
{% if field.help_text %}
|
|
11
|
-
<span class="form-text">{{ field.help_text|safe }}</span>
|
|
12
|
-
{% endif %}
|
|
13
10
|
</label>
|
|
14
11
|
</div>
|
|
15
12
|
{% if bulk_nullable %}
|
|
@@ -18,6 +15,9 @@
|
|
|
18
15
|
<label class="form-check-label" for="{{ field.id_for_label }}_nullify">Set null</label>
|
|
19
16
|
</div>
|
|
20
17
|
{% endif %}
|
|
18
|
+
{% if field.help_text %}
|
|
19
|
+
<span class="form-text">{{ field.help_text|safe }}</span>
|
|
20
|
+
{% endif %}
|
|
21
21
|
{% elif field|widget_type == 'textarea' and not field.label %}
|
|
22
22
|
<div class="col-md-12">
|
|
23
23
|
{{ field }}
|
|
@@ -33,9 +33,6 @@
|
|
|
33
33
|
{% else %}
|
|
34
34
|
<label class="col-md-3 col-form-label{% if field.field.required %} nb-required{% endif %}" for="{{ field.id_for_label }}">
|
|
35
35
|
{{ field.label }}
|
|
36
|
-
{% if field.help_text %}
|
|
37
|
-
<span class="form-text">{{ field.help_text|safe }}</span>
|
|
38
|
-
{% endif %}
|
|
39
36
|
</label>
|
|
40
37
|
<div class="col-md-9">
|
|
41
38
|
{{ field }}
|
|
@@ -45,6 +42,9 @@
|
|
|
45
42
|
<label class="form-check-label" for="{{ field.id_for_label }}_nullify">Set null</label>
|
|
46
43
|
</div>
|
|
47
44
|
{% endif %}
|
|
45
|
+
{% if field.help_text %}
|
|
46
|
+
<span class="form-text">{{ field.help_text|safe }}</span>
|
|
47
|
+
{% endif %}
|
|
48
48
|
{% endif %}
|
|
49
49
|
{% if field.errors %}
|
|
50
50
|
<ul class="mb-0 mt-4">
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
<div class="card">
|
|
27
27
|
<div class="card-header"><strong>Template</strong></div>
|
|
28
28
|
<div class="card-body">
|
|
29
|
-
<div class="mb-10 d-flex
|
|
29
|
+
<div class="mb-10 d-lg-flex">
|
|
30
30
|
<label class="col-lg-3 col-form-label nb-required" for="id_template_code">Jinja Template</label>
|
|
31
31
|
<div class="col-lg-9">
|
|
32
32
|
<textarea cols="40" rows="10" class="form-control" id="id_template_code" required=""></textarea>
|
|
33
33
|
</div>
|
|
34
34
|
</div>
|
|
35
|
-
<div class="mb-10 d-flex
|
|
35
|
+
<div class="mb-10 d-lg-flex">
|
|
36
36
|
<label class="col-lg-3 col-form-label" for="id_context">Data</label>
|
|
37
37
|
<div class="col-lg-9">
|
|
38
38
|
<textarea cols="40" rows="10" class="form-control" placeholder="{}" id="id_context">{}</textarea>
|
|
@@ -75,14 +75,14 @@
|
|
|
75
75
|
</div>
|
|
76
76
|
|
|
77
77
|
<div class="d-print-none justify-content-between mb-n20 nb-form-sticky-footer">
|
|
78
|
-
<button type="reset" class="btn btn-secondary">
|
|
79
|
-
<span aria-hidden="true" class="mdi mdi-close me-4"></span><!--
|
|
80
|
-
-->Clear All
|
|
81
|
-
</button>
|
|
82
78
|
<button type="submit" class="btn btn-primary">
|
|
83
79
|
<span class="mdi mdi-check me-4" aria-hidden="true"></span><!--
|
|
84
80
|
-->Apply Specified
|
|
85
81
|
</button>
|
|
82
|
+
<button type="reset" class="btn btn-secondary">
|
|
83
|
+
<span aria-hidden="true" class="mdi mdi-close me-4"></span><!--
|
|
84
|
+
-->Clear All
|
|
85
|
+
</button>
|
|
86
86
|
</div>
|
|
87
87
|
</form>
|
|
88
88
|
</div>
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
{% export_button content_type list_element=True %}
|
|
57
57
|
</ul>
|
|
58
58
|
</div>
|
|
59
|
-
<div class="
|
|
59
|
+
<div class="dropdown d-inline-flex">
|
|
60
60
|
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
|
61
61
|
Actions
|
|
62
62
|
</button>
|
|
@@ -234,11 +234,11 @@
|
|
|
234
234
|
<div class="mb-10 d-flex justify-content-center">
|
|
235
235
|
<label class="col-md-3 col-form-label nb-required" for="id_status">
|
|
236
236
|
Status
|
|
237
|
-
<span class="form-text">Help text for this form field</span>
|
|
238
237
|
</label>
|
|
239
238
|
<div class="col-md-9">
|
|
240
239
|
<select name="status" class="nautobot-select2-api form-control select2-hidden-accessible" data-query-param-content_types="["dcim.device"]" display-field="display" value-field="id" data-depth="0" required="" placeholder="Status" data-url="/api/extras/statuses/" id="id_status">
|
|
241
240
|
</select>
|
|
241
|
+
<span class="form-text">Help text for this form field</span>
|
|
242
242
|
</div>
|
|
243
243
|
</div>
|
|
244
244
|
</div>
|
|
@@ -471,6 +471,15 @@
|
|
|
471
471
|
<button type="button" class="btn btn-link disabled">Link</button>
|
|
472
472
|
</td>
|
|
473
473
|
</tr>
|
|
474
|
+
<tr>
|
|
475
|
+
<td><code>btn-group</code> like radio buttons</td>
|
|
476
|
+
<td>
|
|
477
|
+
<div class="btn-group" role="group">
|
|
478
|
+
<button type="button" class="btn btn-primary bg-primary nb-text-body-bg">Current Active Option</button>
|
|
479
|
+
<button type="button" class="btn btn-primary">Alternative Option</button>
|
|
480
|
+
</div>
|
|
481
|
+
</td>
|
|
482
|
+
</tr>
|
|
474
483
|
</table>
|
|
475
484
|
</div>
|
|
476
485
|
</div>
|
|
@@ -1120,13 +1129,14 @@ This:
|
|
|
1120
1129
|
<h1>Nautobot Icons</h1>
|
|
1121
1130
|
<div class="row">
|
|
1122
1131
|
<div class="col-12">
|
|
1123
|
-
<div class="column-gap-8 d-flex flex-wrap px-20 py-16 rounded row-gap-16" style="background-color: #
|
|
1132
|
+
<div class="column-gap-8 d-flex flex-wrap px-20 py-16 rounded row-gap-16" style="background-color: #121212;">
|
|
1124
1133
|
<div class="icon-preview"><img alt="360-degrees icon" src="{% static 'nautobot-icons/360-degrees.svg' %}">360-degrees</div>
|
|
1125
1134
|
<div class="icon-preview"><img alt="arrow-decision icon" src="{% static 'nautobot-icons/arrow-decision.svg' %}">arrow-decision</div>
|
|
1126
1135
|
<div class="icon-preview"><img alt="arrows-expand-rec icon" src="{% static 'nautobot-icons/arrows-expand-rec.svg' %}">arrows-expand-rec</div>
|
|
1127
1136
|
<div class="icon-preview"><img alt="arrows-move-rec icon" src="{% static 'nautobot-icons/arrows-move-rec.svg' %}">arrows-move-rec</div>
|
|
1128
1137
|
<div class="icon-preview"><img alt="arrows-move-2-rec icon" src="{% static 'nautobot-icons/arrows-move-2-rec.svg' %}">arrows-move-2-rec</div>
|
|
1129
1138
|
<div class="icon-preview"><img alt="atom icon" src="{% static 'nautobot-icons/atom.svg' %}">atom</div>
|
|
1139
|
+
<div class="icon-preview"><img alt="power icon" src="{% static 'nautobot-icons/battery-3.svg' %}">battery-3</div>
|
|
1130
1140
|
<div class="icon-preview"><img alt="branch icon" src="{% static 'nautobot-icons/branch.svg' %}">branch</div>
|
|
1131
1141
|
<div class="icon-preview"><img alt="briefcase-2 icon" src="{% static 'nautobot-icons/briefcase-2.svg' %}">briefcase-2</div>
|
|
1132
1142
|
<div class="icon-preview"><img alt="cable-data icon" src="{% static 'nautobot-icons/cable-data.svg' %}">cable-data</div>
|
|
@@ -1145,6 +1155,7 @@ This:
|
|
|
1145
1155
|
<div class="icon-preview"><img alt="device-lifecycle icon" src="{% static 'nautobot-icons/device-lifecycle.svg' %}">device-lifecycle</div>
|
|
1146
1156
|
<div class="icon-preview"><img alt="direction icon" src="{% static 'nautobot-icons/direction.svg' %}">direction</div>
|
|
1147
1157
|
<div class="icon-preview"><img alt="elements icon" src="{% static 'nautobot-icons/elements.svg' %}">elements</div>
|
|
1158
|
+
<div class="icon-preview"><img alt="extensibility icon" src="{% static 'nautobot-icons/extensibility.svg' %}">extensibility</div>
|
|
1148
1159
|
<div class="icon-preview"><img alt="globe icon" src="{% static 'nautobot-icons/globe.svg' %}">globe</div>
|
|
1149
1160
|
<div class="icon-preview"><img alt="globe-2 icon" src="{% static 'nautobot-icons/globe-2.svg' %}">globe-2</div>
|
|
1150
1161
|
<div class="icon-preview"><img alt="hammer icon" src="{% static 'nautobot-icons/hammer.svg' %}">hammer</div>
|
|
@@ -1154,6 +1165,7 @@ This:
|
|
|
1154
1165
|
<div class="icon-preview"><img alt="lightning icon" src="{% static 'nautobot-icons/lightning.svg' %}">lightning</div>
|
|
1155
1166
|
<div class="icon-preview"><img alt="list-unordered icon" src="{% static 'nautobot-icons/list-unordered.svg' %}">list-unordered</div>
|
|
1156
1167
|
<div class="icon-preview"><img alt="map-view icon" src="{% static 'nautobot-icons/map-view.svg' %}">map-view</div>
|
|
1168
|
+
<div class="icon-preview"><img alt="organization icon" src="{% static 'nautobot-icons/organization.svg' %}">organization</div>
|
|
1157
1169
|
<div class="icon-preview"><img alt="pin-2 icon" src="{% static 'nautobot-icons/pin-2.svg' %}">pin-2</div>
|
|
1158
1170
|
<div class="icon-preview"><img alt="pin-3 icon" src="{% static 'nautobot-icons/pin-3.svg' %}">pin-3</div>
|
|
1159
1171
|
<div class="icon-preview"><img alt="plug icon" src="{% static 'nautobot-icons/plug.svg' %}">plug</div>
|
|
@@ -1162,6 +1174,7 @@ This:
|
|
|
1162
1174
|
<div class="icon-preview"><img alt="rotate-cw icon" src="{% static 'nautobot-icons/rotate-cw.svg' %}">rotate-cw</div>
|
|
1163
1175
|
<div class="icon-preview"><img alt="route icon" src="{% static 'nautobot-icons/route.svg' %}">route</div>
|
|
1164
1176
|
<div class="icon-preview"><img alt="secrets icon" src="{% static 'nautobot-icons/secrets.svg' %}">secrets</div>
|
|
1177
|
+
<div class="icon-preview"><img alt="security icon" src="{% static 'nautobot-icons/security.svg' %}">security</div>
|
|
1165
1178
|
<div class="icon-preview"><img alt="server icon" src="{% static 'nautobot-icons/server.svg' %}">server</div>
|
|
1166
1179
|
<div class="icon-preview"><img alt="server-2 icon" src="{% static 'nautobot-icons/server-2.svg' %}">server-2</div>
|
|
1167
1180
|
<div class="icon-preview"><img alt="share icon" src="{% static 'nautobot-icons/share.svg' %}">share</div>
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
<option value="{{ widget.value }}"
|
|
1
|
+
<option value="{{ widget.value }}"
|
|
2
|
+
{% include "django/forms/widgets/attrs.html" %}
|
|
3
|
+
{% if widget.label.disabled %} disabled{% endif %}>{{ widget.label.label|default:widget.label }}</option>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from collections.abc import Iterable
|
|
2
2
|
import datetime
|
|
3
|
+
from importlib import resources
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
5
6
|
import re
|
|
@@ -7,6 +8,7 @@ from typing import Literal
|
|
|
7
8
|
from urllib.parse import parse_qs, quote_plus
|
|
8
9
|
|
|
9
10
|
from django import template
|
|
11
|
+
from django.apps import apps
|
|
10
12
|
from django.conf import settings
|
|
11
13
|
from django.contrib import messages
|
|
12
14
|
from django.contrib.auth.models import AnonymousUser
|
|
@@ -14,9 +16,11 @@ from django.contrib.staticfiles.finders import find
|
|
|
14
16
|
from django.core.exceptions import ObjectDoesNotExist
|
|
15
17
|
from django.templatetags.static import static, StaticNode
|
|
16
18
|
from django.urls import NoReverseMatch, reverse
|
|
19
|
+
from django.utils.formats import date_format
|
|
17
20
|
from django.utils.html import format_html, format_html_join, strip_tags
|
|
18
21
|
from django.utils.safestring import mark_safe
|
|
19
22
|
from django.utils.text import slugify as django_slugify
|
|
23
|
+
from django.utils.translation import gettext as _
|
|
20
24
|
from django_jinja import library
|
|
21
25
|
from markdown import markdown
|
|
22
26
|
import yaml
|
|
@@ -483,11 +487,13 @@ def percentage(x, y):
|
|
|
483
487
|
@library.filter()
|
|
484
488
|
@register.filter()
|
|
485
489
|
def get_docs_url(model):
|
|
486
|
-
"""Return the
|
|
490
|
+
"""Return the documentation URL for the specified model, if it can be found/predicted.
|
|
487
491
|
|
|
488
492
|
- Core models, as of 2.0, are usually at `docs/user-guide/core-data-model/{app_label}/{model_name}.html`.
|
|
489
493
|
- Models in the `extras` app are usually at `docs/user-guide/platform-functionality/{model_name}.html`.
|
|
490
|
-
- Apps (plugins) are
|
|
494
|
+
- Apps (plugins) are expected to be documented within their package at
|
|
495
|
+
``docs/models/{model_name}.html`` and are served dynamically through
|
|
496
|
+
the ``AppDocsView`` endpoint (``/docs/<app_name>/<path>``).
|
|
491
497
|
|
|
492
498
|
Any model can define a `documentation_static_path` class attribute if it needs to override the above expectations.
|
|
493
499
|
|
|
@@ -502,10 +508,26 @@ def get_docs_url(model):
|
|
|
502
508
|
Example:
|
|
503
509
|
>>> get_docs_url(location_instance)
|
|
504
510
|
"static/docs/models/dcim/location.html"
|
|
511
|
+
>>> get_docs_url(example_model)
|
|
512
|
+
"/docs/example-app/models/examplemodel.html"
|
|
505
513
|
"""
|
|
506
514
|
if hasattr(model, "documentation_static_path"):
|
|
507
515
|
path = model.documentation_static_path
|
|
508
516
|
elif model._meta.app_label in settings.PLUGINS:
|
|
517
|
+
app_label = model._meta.app_label
|
|
518
|
+
app_config = apps.get_app_config(app_label)
|
|
519
|
+
app_base_url = getattr(app_config, "base_url", None) or app_config.label
|
|
520
|
+
path = f"models/{model._meta.model_name}.html"
|
|
521
|
+
# Check that the file actually exists inside the app's docs folder
|
|
522
|
+
try:
|
|
523
|
+
base_dir = resources.files(app_label) / "docs"
|
|
524
|
+
file_path = base_dir / path
|
|
525
|
+
if file_path.is_file():
|
|
526
|
+
return reverse("docs_file", kwargs={"app_base_url": app_base_url, "path": path})
|
|
527
|
+
except ModuleNotFoundError:
|
|
528
|
+
pass
|
|
529
|
+
logger.debug("No documentation found for %s (expected at %s)", type(model), path)
|
|
530
|
+
# define path to try to get static
|
|
509
531
|
path = f"{model._meta.app_label}/docs/models/{model._meta.model_name}.html"
|
|
510
532
|
elif model._meta.app_label == "extras":
|
|
511
533
|
path = f"docs/user-guide/platform-functionality/{model._meta.model_name}.html"
|
|
@@ -759,7 +781,7 @@ def render_address(address):
|
|
|
759
781
|
quote_plus(address),
|
|
760
782
|
)
|
|
761
783
|
address = format_html_join("", "{}<br>", ((line,) for line in address.split("\n")))
|
|
762
|
-
return format_html('<div class="
|
|
784
|
+
return format_html('<div class="float-end d-print-none">{}</div>{}', map_link, address)
|
|
763
785
|
return HTML_NONE
|
|
764
786
|
|
|
765
787
|
|
|
@@ -798,7 +820,11 @@ def render_button_class(value):
|
|
|
798
820
|
"""
|
|
799
821
|
if value:
|
|
800
822
|
base = value.split()[0]
|
|
801
|
-
return format_html(
|
|
823
|
+
return format_html(
|
|
824
|
+
'<button class="btn btn-{}">{}</button>',
|
|
825
|
+
base.lower() if base.lower() != "default" else "secondary",
|
|
826
|
+
base.capitalize(),
|
|
827
|
+
)
|
|
802
828
|
return ""
|
|
803
829
|
|
|
804
830
|
|
|
@@ -831,6 +857,26 @@ def label_list(value, suffix=""):
|
|
|
831
857
|
)
|
|
832
858
|
|
|
833
859
|
|
|
860
|
+
@library.filter()
|
|
861
|
+
@register.filter()
|
|
862
|
+
def format_timezone(time_zone):
|
|
863
|
+
"""
|
|
864
|
+
Return a human-readable representation of a time zone including:
|
|
865
|
+
- Time zone name and UTC offset on the first line
|
|
866
|
+
- Local date and time on the next line (in smaller font)
|
|
867
|
+
"""
|
|
868
|
+
if not time_zone:
|
|
869
|
+
return HTML_NONE
|
|
870
|
+
|
|
871
|
+
now = datetime.datetime.now(time_zone)
|
|
872
|
+
|
|
873
|
+
# Locale-aware formatting (respects USE_L10N + active locale)
|
|
874
|
+
local_time = date_format(now, format="DATETIME_FORMAT", use_l10n=True)
|
|
875
|
+
|
|
876
|
+
result = f"{time_zone} (UTC {now.strftime('%z')})<br><small>{_('Local time')}: {local_time}</small>"
|
|
877
|
+
return format_html(result)
|
|
878
|
+
|
|
879
|
+
|
|
834
880
|
#
|
|
835
881
|
# Tags
|
|
836
882
|
#
|
|
@@ -899,7 +945,7 @@ def django_querystring(context, query_dict=None, **kwargs):
|
|
|
899
945
|
{% django_querystring my_query_dict foo=3 %}
|
|
900
946
|
"""
|
|
901
947
|
if query_dict is None:
|
|
902
|
-
query_dict = context
|
|
948
|
+
query_dict = context["request"].GET
|
|
903
949
|
params = query_dict.copy()
|
|
904
950
|
for key, value in kwargs.items():
|
|
905
951
|
if value is None:
|
|
@@ -932,7 +978,7 @@ def table_config_button(table, table_name=None, extra_classes="", disabled=False
|
|
|
932
978
|
<span class="mdi mdi-cog" aria-hidden="true"></span>
|
|
933
979
|
<span class="visually-hidden">Configure</span>
|
|
934
980
|
</button>"""
|
|
935
|
-
return format_html(html_template, extra_classes, table_name,
|
|
981
|
+
return format_html(html_template, extra_classes, table_name, "disabled" if disabled else "", table_name)
|
|
936
982
|
|
|
937
983
|
|
|
938
984
|
@register.inclusion_tag("utilities/templatetags/utilization_graph.html")
|