nautobot 2.0.0a3__py3-none-any.whl → 2.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -117
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/forms.py +0 -65
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
- nautobot/circuits/migrations/0016_tagsfield.py +34 -0
- nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
- nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
- nautobot/circuits/models.py +3 -87
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +39 -1
- nautobot/circuits/tests/integration/test_relationships.py +9 -9
- nautobot/circuits/tests/test_api.py +4 -8
- nautobot/circuits/tests/test_filters.py +10 -4
- nautobot/circuits/tests/test_models.py +5 -1
- nautobot/circuits/tests/test_views.py +27 -5
- nautobot/circuits/views.py +18 -10
- nautobot/core/api/__init__.py +8 -2
- nautobot/core/api/fields.py +15 -6
- nautobot/core/api/filter_backends.py +3 -2
- nautobot/core/api/metadata.py +237 -30
- nautobot/core/api/mixins.py +94 -0
- nautobot/core/api/pagination.py +4 -0
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +46 -2
- nautobot/core/api/serializers.py +377 -35
- nautobot/core/api/urls.py +11 -3
- nautobot/core/api/utils.py +174 -2
- nautobot/core/api/versioning.py +32 -10
- nautobot/core/api/views.py +266 -72
- nautobot/core/apps/__init__.py +138 -220
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -12
- nautobot/core/celery/control.py +46 -0
- nautobot/core/celery/encoders.py +53 -0
- nautobot/core/celery/log.py +38 -0
- nautobot/core/celery/schedulers.py +23 -4
- nautobot/core/celery/task.py +1 -16
- nautobot/core/checks.py +0 -27
- nautobot/core/choices.py +0 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -1
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +0 -24
- nautobot/core/context_processors.py +12 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/forms/__init__.py +0 -4
- nautobot/core/forms/fields.py +38 -65
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/forms/utils.py +0 -52
- nautobot/core/graphql/schema.py +4 -27
- nautobot/core/jobs/__init__.py +75 -0
- nautobot/core/management/commands/build_ui.py +255 -0
- nautobot/core/management/commands/generate_test_data.py +3 -2
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -42
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +0 -14
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +5 -6
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +80 -42
- nautobot/core/tables.py +5 -5
- nautobot/core/tasks.py +4 -7
- nautobot/core/templates/base.html +1 -49
- nautobot/core/templates/base_django.html +49 -0
- nautobot/core/templates/base_react.html +55 -0
- nautobot/core/templates/buttons/export.html +6 -4
- nautobot/core/templates/generic/object_bulk_create.html +10 -21
- nautobot/core/templates/generic/object_list.html +3 -1
- nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/javascript.html +0 -14
- nautobot/core/templates/inc/nav_menu.html +28 -33
- nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
- nautobot/core/templates/inc/relationships_table_rows.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +8 -20
- nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
- nautobot/core/templates/rest_framework/api.html +8 -0
- nautobot/core/templatetags/buttons.py +32 -28
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +362 -47
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -9
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +21 -46
- nautobot/core/tests/integration/test_filters.py +17 -8
- nautobot/core/tests/integration/test_navbar.py +11 -34
- nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
- nautobot/core/tests/nautobot_config.py +2 -3
- nautobot/core/tests/test_api.py +290 -21
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_filters.py +107 -59
- nautobot/core/tests/test_forms.py +26 -92
- nautobot/core/tests/test_graphql.py +110 -77
- nautobot/core/tests/test_logging.py +4 -0
- nautobot/core/tests/test_managers.py +3 -1
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +4 -4
- nautobot/core/tests/test_utils.py +32 -68
- nautobot/core/tests/test_views.py +12 -15
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +9 -6
- nautobot/core/utils/filtering.py +8 -3
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +1 -104
- nautobot/core/views/__init__.py +1 -0
- nautobot/core/views/generic.py +75 -110
- nautobot/core/views/mixins.py +52 -61
- nautobot/core/views/renderers.py +6 -7
- nautobot/core/views/utils.py +80 -0
- nautobot/dcim/api/serializers.py +160 -667
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -44
- nautobot/dcim/choices.py +2 -0
- nautobot/dcim/filters/__init__.py +21 -0
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +19 -765
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +3 -33
- nautobot/dcim/models/device_component_templates.py +6 -0
- nautobot/dcim/models/device_components.py +12 -198
- nautobot/dcim/models/devices.py +30 -143
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -50
- nautobot/dcim/models/racks.py +7 -84
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +1 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/location.html +16 -1
- nautobot/dcim/templates/dcim/locationtype.html +15 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/rackgroup.html +0 -12
- nautobot/dcim/tests/test_api.py +166 -81
- nautobot/dcim/tests/test_cablepaths.py +41 -35
- nautobot/dcim/tests/test_filters.py +67 -23
- nautobot/dcim/tests/test_forms.py +5 -205
- nautobot/dcim/tests/test_graphql.py +7 -2
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +182 -110
- nautobot/dcim/tests/test_natural_ordering.py +11 -8
- nautobot/dcim/tests/test_signals.py +6 -3
- nautobot/dcim/tests/test_views.py +197 -175
- nautobot/dcim/urls.py +11 -16
- nautobot/dcim/views.py +7 -134
- nautobot/docs/additional-features/caching.md +6 -87
- nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
- nautobot/docs/additional-features/jobs.md +177 -195
- nautobot/docs/administration/nautobot-server.md +6 -21
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/optional-settings.md +32 -41
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +55 -5
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/index.md +3 -2
- nautobot/docs/installation/migrating-from-netbox.md +11 -42
- nautobot/docs/installation/nautobot.md +1 -1
- nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
- nautobot/docs/models/dcim/device.md +3 -0
- nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
- nautobot/docs/models/extras/computedfield.md +4 -4
- nautobot/docs/models/extras/gitrepository.md +3 -0
- nautobot/docs/models/extras/job.md +1 -0
- nautobot/docs/models/extras/jobbutton.md +18 -13
- nautobot/docs/models/extras/jobhook.md +7 -4
- nautobot/docs/models/extras/jobresult.md +6 -2
- nautobot/docs/models/extras/relationship.md +2 -2
- nautobot/docs/models/extras/status.md +6 -19
- nautobot/docs/models/ipam/ipaddress.md +3 -0
- nautobot/docs/models/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +83 -21
- nautobot/docs/release-notes/version-1.5.md +53 -0
- nautobot/docs/release-notes/version-2.0.md +180 -0
- nautobot/docs/requirements.txt +1 -0
- nautobot/docs/rest-api/overview.md +384 -215
- nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
- nautobot/extras/admin.py +3 -5
- nautobot/extras/api/customfields.py +15 -39
- nautobot/extras/api/fields.py +0 -11
- nautobot/extras/api/mixins.py +45 -0
- nautobot/extras/api/relationships.py +63 -158
- nautobot/extras/api/serializers.py +165 -700
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +294 -280
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -9
- nautobot/extras/constants.py +9 -3
- nautobot/extras/datasources/__init__.py +2 -0
- nautobot/extras/datasources/git.py +135 -186
- nautobot/extras/datasources/registry.py +25 -35
- nautobot/extras/filters/__init__.py +20 -19
- nautobot/extras/filters/mixins.py +4 -4
- nautobot/extras/forms/forms.py +63 -127
- nautobot/extras/forms/mixins.py +23 -51
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -565
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/managers.py +30 -7
- nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
- nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
- nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
- nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
- nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
- nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
- nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
- nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
- nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
- nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
- nautobot/extras/migrations/0079_tagsfield.py +28 -0
- nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
- nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
- nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
- nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
- nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
- nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
- nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
- nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
- nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
- nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
- nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
- nautobot/extras/models/__init__.py +2 -3
- nautobot/extras/models/change_logging.py +0 -36
- nautobot/extras/models/customfields.py +39 -33
- nautobot/extras/models/datasources.py +48 -50
- nautobot/extras/models/groups.py +5 -6
- nautobot/extras/models/jobs.py +189 -321
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +0 -19
- nautobot/extras/models/relationships.py +19 -13
- nautobot/extras/models/roles.py +0 -34
- nautobot/extras/models/secrets.py +2 -26
- nautobot/extras/models/statuses.py +6 -5
- nautobot/extras/models/tags.py +2 -17
- nautobot/extras/navigation.py +89 -307
- nautobot/extras/plugins/__init__.py +3 -120
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -3
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +34 -40
- nautobot/extras/tasks.py +0 -12
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +16 -1
- nautobot/extras/templates/extras/customfield.html +0 -13
- nautobot/extras/templates/extras/gitrepository.html +3 -3
- nautobot/extras/templates/extras/inc/jobresult.html +10 -0
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/job.html +35 -25
- nautobot/extras/templates/extras/job_approval_request.html +15 -30
- nautobot/extras/templates/extras/job_detail.html +13 -31
- nautobot/extras/templates/extras/job_edit.html +15 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templatetags/job_buttons.py +1 -0
- nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
- nautobot/extras/test_jobs/atomic_transaction.py +53 -0
- nautobot/extras/test_jobs/dry_run.py +29 -0
- nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
- nautobot/extras/test_jobs/duplicate_name2.py +9 -0
- nautobot/extras/test_jobs/fail.py +23 -0
- nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
- nautobot/extras/test_jobs/file_upload_pass.py +25 -0
- nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
- nautobot/extras/test_jobs/job_button_receiver.py +28 -0
- nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
- nautobot/extras/test_jobs/job_variables.py +88 -0
- nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
- nautobot/extras/test_jobs/log_redaction.py +20 -0
- nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
- nautobot/extras/test_jobs/modify_db.py +25 -0
- nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
- nautobot/extras/test_jobs/object_var_optional.py +21 -0
- nautobot/extras/test_jobs/object_var_required.py +21 -0
- nautobot/extras/test_jobs/object_vars.py +26 -0
- nautobot/extras/test_jobs/pass.py +25 -0
- nautobot/extras/test_jobs/profiling.py +32 -0
- nautobot/extras/test_jobs/read_only_job.py +15 -0
- nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
- nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
- nautobot/extras/tests/integration/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +649 -642
- nautobot/extras/tests/test_changelog.py +3 -3
- nautobot/extras/tests/test_context_managers.py +5 -3
- nautobot/extras/tests/test_customfields.py +92 -50
- nautobot/extras/tests/test_datasources.py +189 -112
- nautobot/extras/tests/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/test_filters.py +137 -89
- nautobot/extras/tests/test_forms.py +73 -75
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +262 -263
- nautobot/extras/tests/test_migrations.py +4 -3
- nautobot/extras/tests/test_models.py +116 -161
- nautobot/extras/tests/test_plugins.py +38 -60
- nautobot/extras/tests/test_relationships.py +167 -120
- nautobot/extras/tests/test_tags.py +6 -11
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +201 -145
- nautobot/extras/tests/test_webhooks.py +6 -2
- nautobot/extras/urls.py +42 -42
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +78 -152
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +58 -164
- nautobot/ipam/api/urls.py +1 -1
- nautobot/ipam/api/views.py +3 -2
- nautobot/ipam/apps.py +1 -2
- nautobot/ipam/filters.py +1 -10
- nautobot/ipam/forms.py +4 -177
- nautobot/ipam/lookups.py +1 -0
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
- nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
- nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
- nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
- nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
- nautobot/ipam/models.py +100 -236
- nautobot/ipam/navigation.py +36 -181
- nautobot/ipam/querysets.py +20 -25
- nautobot/ipam/signals.py +49 -6
- nautobot/ipam/tables.py +10 -3
- nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
- nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
- nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
- nautobot/ipam/tests/integration/test_prefixes.py +3 -26
- nautobot/ipam/tests/test_api.py +22 -19
- nautobot/ipam/tests/test_filters.py +59 -23
- nautobot/ipam/tests/test_migrations.py +6 -10
- nautobot/ipam/tests/test_models.py +323 -198
- nautobot/ipam/tests/test_ordering.py +2 -2
- nautobot/ipam/tests/test_querysets.py +44 -24
- nautobot/ipam/tests/test_views.py +73 -26
- nautobot/ipam/urls.py +16 -0
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +137 -20
- nautobot/project-static/docs/404.html +1178 -10
- nautobot/project-static/docs/additional-features/caching.html +1224 -159
- nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
- nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
- nautobot/project-static/docs/additional-features/graphql.html +1179 -11
- nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
- nautobot/project-static/docs/additional-features/jobs.html +1514 -328
- nautobot/project-static/docs/additional-features/napalm.html +1180 -12
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
- nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
- nautobot/project-static/docs/administration/celery-queues.html +1178 -10
- nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
- nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
- nautobot/project-static/docs/administration/permissions.html +1178 -10
- nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
- nautobot/project-static/docs/apps/index.html +1178 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
- nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
- nautobot/project-static/docs/configuration/index.html +1178 -10
- nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
- nautobot/project-static/docs/configuration/required-settings.html +1312 -211
- nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
- nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
- nautobot/project-static/docs/core-functionality/devices.html +1182 -10
- nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
- nautobot/project-static/docs/core-functionality/power.html +1178 -10
- nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
- nautobot/project-static/docs/core-functionality/services.html +1178 -10
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
- nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
- nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
- nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
- nautobot/project-static/docs/development/application-registry.html +1190 -42
- nautobot/project-static/docs/development/best-practices.html +1178 -10
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
- nautobot/project-static/docs/development/extending-models.html +1238 -83
- nautobot/project-static/docs/development/generic-views.html +1180 -14
- nautobot/project-static/docs/development/getting-started.html +1365 -90
- nautobot/project-static/docs/development/homepage.html +1178 -10
- nautobot/project-static/docs/development/index.html +1178 -10
- nautobot/project-static/docs/development/model-features.html +1178 -10
- nautobot/project-static/docs/development/natural-keys.html +1178 -10
- nautobot/project-static/docs/development/navigation-menu.html +1215 -125
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1178 -10
- nautobot/project-static/docs/development/role-internals.html +1179 -12
- nautobot/project-static/docs/development/style-guide.html +1188 -19
- nautobot/project-static/docs/development/templates.html +1178 -10
- nautobot/project-static/docs/development/testing.html +1178 -10
- nautobot/project-static/docs/development/user-preferences.html +1178 -10
- nautobot/project-static/docs/docker/index.html +1178 -10
- nautobot/project-static/docs/index.html +1183 -12
- nautobot/project-static/docs/installation/centos.html +1178 -10
- nautobot/project-static/docs/installation/external-authentication.html +1178 -10
- nautobot/project-static/docs/installation/http-server.html +1178 -10
- nautobot/project-static/docs/installation/index.html +1178 -10
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
- nautobot/project-static/docs/installation/nautobot.html +1179 -11
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
- nautobot/project-static/docs/installation/services.html +1178 -10
- nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/project-static/docs/installation/ubuntu.html +1178 -10
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
- nautobot/project-static/docs/installation/upgrading.html +1178 -10
- nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
- nautobot/project-static/docs/models/circuits/provider.html +1293 -103
- nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
- nautobot/project-static/docs/models/dcim/cable.html +1324 -103
- nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/device.html +1326 -132
- nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
- nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/interface.html +1293 -103
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
- nautobot/project-static/docs/models/dcim/location.html +1293 -103
- nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
- nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
- nautobot/project-static/docs/models/dcim/platform.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
- nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/rack.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
- nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
- nautobot/project-static/docs/models/dcim/region.html +1178 -10
- nautobot/project-static/docs/models/dcim/site.html +1178 -10
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
- nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
- nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
- nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
- nautobot/project-static/docs/models/extras/customfield.html +1180 -12
- nautobot/project-static/docs/models/extras/customlink.html +1180 -12
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
- nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
- nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
- nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
- nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
- nautobot/project-static/docs/models/extras/job.html +1277 -86
- nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
- nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
- nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
- nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
- nautobot/project-static/docs/models/extras/note.html +1180 -12
- nautobot/project-static/docs/models/extras/relationship.html +1182 -14
- nautobot/project-static/docs/models/extras/role.html +1320 -86
- nautobot/project-static/docs/models/extras/secret.html +1314 -86
- nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
- nautobot/project-static/docs/models/extras/status.html +1188 -59
- nautobot/project-static/docs/models/extras/tag.html +1180 -12
- nautobot/project-static/docs/models/extras/webhook.html +1180 -12
- nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
- nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
- nautobot/project-static/docs/models/ipam/rir.html +1276 -86
- nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
- nautobot/project-static/docs/models/ipam/service.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
- nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
- nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
- nautobot/project-static/docs/models/users/token.html +1276 -86
- nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
- nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1726 -495
- nautobot/project-static/docs/plugins/index.html +1178 -10
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
- nautobot/project-static/docs/release-notes/index.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
- nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
- nautobot/project-static/docs/requirements.txt +1 -0
- nautobot/project-static/docs/rest-api/authentication.html +1179 -11
- nautobot/project-static/docs/rest-api/filtering.html +1178 -10
- nautobot/project-static/docs/rest-api/overview.html +1841 -446
- nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +197 -187
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
- nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
- nautobot/project-static/docs/user-guides/graphql.html +1178 -10
- nautobot/project-static/docs/user-guides/relationships.html +1178 -10
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -32
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/forms.py +0 -28
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -25
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -3
- nautobot/tenancy/tests/test_filters.py +10 -5
- nautobot/tenancy/views.py +0 -2
- nautobot/ui/.eslintignore +6 -0
- nautobot/ui/.gitignore +10 -0
- nautobot/ui/.prettierignore +9 -0
- nautobot/ui/.prettierrc +4 -0
- nautobot/ui/README.md +33 -0
- nautobot/ui/app_imports.js.j2 +7 -0
- nautobot/ui/craco.config.js +46 -0
- nautobot/ui/jsconfig-base.json +11 -0
- nautobot/ui/jsconfig.json +5 -0
- nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
- nautobot/ui/package-lock.json +21451 -0
- nautobot/ui/package.json +70 -0
- nautobot/ui/public/index.html +47 -0
- nautobot/ui/public/logo192.png +0 -0
- nautobot/ui/public/logo512.png +0 -0
- nautobot/ui/public/manifest.json +25 -0
- nautobot/ui/public/nautobot_logo.svg +131 -0
- nautobot/ui/public/robots.txt +3 -0
- nautobot/ui/src/App.js +71 -0
- nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
- nautobot/ui/src/components/AppTab.js +40 -0
- nautobot/ui/src/components/Apps.js +60 -0
- nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
- nautobot/ui/src/components/HomePanel.js +58 -0
- nautobot/ui/src/components/JobHistoryTable.js +78 -0
- nautobot/ui/src/components/Layout.js +53 -0
- nautobot/ui/src/components/LoadingWidget.js +25 -0
- nautobot/ui/src/components/Navbar.js +116 -0
- nautobot/ui/src/components/NotificationPopover.js +27 -0
- nautobot/ui/src/components/ObjectListTable.js +209 -0
- nautobot/ui/src/components/ReferenceDataTag.js +35 -0
- nautobot/ui/src/components/RouterButton.js +10 -0
- nautobot/ui/src/components/RouterLink.js +10 -0
- nautobot/ui/src/components/SidebarNav.js +147 -0
- nautobot/ui/src/components/Table.js +48 -0
- nautobot/ui/src/components/TableItem.js +71 -0
- nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
- nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
- nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
- nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
- nautobot/ui/src/components/__tests__/Table.test.js +36 -0
- nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
- nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
- nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
- nautobot/ui/src/components/pagination.js +93 -0
- nautobot/ui/src/components/paginator.js +79 -0
- nautobot/ui/src/components/paginator_form.js +43 -0
- nautobot/ui/src/components/usePagination.js +57 -0
- nautobot/ui/src/constants/apiPath.js +10 -0
- nautobot/ui/src/constants/icons.js +15 -0
- nautobot/ui/src/constants/size.js +15 -0
- nautobot/ui/src/index.js +65 -0
- nautobot/ui/src/reportWebVitals.js +15 -0
- nautobot/ui/src/router.js +77 -0
- nautobot/ui/src/utils/api.js +131 -0
- nautobot/ui/src/utils/app-import.js +15 -0
- nautobot/ui/src/utils/color.js +15 -0
- nautobot/ui/src/utils/date.js +14 -0
- nautobot/ui/src/utils/index.js +15 -0
- nautobot/ui/src/utils/navigation.js +32 -0
- nautobot/ui/src/utils/session.js +64 -0
- nautobot/ui/src/utils/store.js +242 -0
- nautobot/ui/src/utils/string.js +6 -0
- nautobot/ui/src/utils/url.js +4 -0
- nautobot/ui/src/views/Home.js +138 -0
- nautobot/ui/src/views/InstalledApps.js +80 -0
- nautobot/ui/src/views/Login.js +48 -0
- nautobot/ui/src/views/Logout.js +20 -0
- nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
- nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
- nautobot/ui/src/views/__tests__/Login.test.js +15 -0
- nautobot/ui/src/views/generic/GenericView.js +142 -0
- nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
- nautobot/ui/src/views/generic/ObjectList.js +127 -0
- nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +51 -61
- nautobot/users/api/urls.py +1 -1
- nautobot/users/api/views.py +53 -2
- nautobot/users/tests/test_api.py +110 -25
- nautobot/virtualization/api/serializers.py +18 -130
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/forms.py +13 -99
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
- nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
- nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
- nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +31 -123
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +25 -26
- nautobot/virtualization/tests/test_filters.py +41 -15
- nautobot/virtualization/tests/test_models.py +31 -7
- nautobot/virtualization/tests/test_views.py +42 -25
- nautobot/virtualization/views.py +7 -6
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
- nautobot/circuits/api/nested_serializers.py +0 -69
- nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
- nautobot/dcim/api/nested_serializers.py +0 -356
- nautobot/dcim/templates/dcim/device_import.html +0 -5
- nautobot/dcim/templates/dcim/device_import_child.html +0 -5
- nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
- nautobot/extras/api/nested_serializers.py +0 -353
- nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
- nautobot/extras/reports.py +0 -60
- nautobot/extras/scripts.py +0 -72
- nautobot/extras/tests/example_jobs/script_variables.py +0 -67
- nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
- nautobot/extras/tests/example_jobs/test_fail.py +0 -16
- nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
- nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
- nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
- nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
- nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
- nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
- nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
- nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
- nautobot/extras/tests/example_jobs/test_pass.py +0 -19
- nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
- nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
- nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
- nautobot/ipam/api/nested_serializers.py +0 -159
- nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
- nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
- nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
- nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
- nautobot/tenancy/api/nested_serializers.py +0 -31
- nautobot/users/api/nested_serializers.py +0 -67
- nautobot/virtualization/api/nested_serializers.py +0 -65
- /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
- /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -34,8 +34,20 @@ def settings(request):
|
|
|
34
34
|
Expose Django settings in the template context. Example: {{ settings.DEBUG }}
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
+
use_new_ui = request.COOKIES.get("newui", False)
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
view_class = request.resolver_match.func.view_class
|
|
41
|
+
use_new_ui = use_new_ui and getattr(view_class, "use_new_ui", False)
|
|
42
|
+
except AttributeError:
|
|
43
|
+
# Use this method to import the view class views that inherits from
|
|
44
|
+
# NautobotUIViewSet, as this views do not have the 'view_class' attribute.
|
|
45
|
+
if hasattr(request, "accepted_renderer"):
|
|
46
|
+
use_new_ui = use_new_ui and getattr(request.accepted_renderer, "use_new_ui", False)
|
|
47
|
+
|
|
37
48
|
return {
|
|
38
49
|
"settings": django_settings,
|
|
50
|
+
"root_template": "base_react.html" if use_new_ui else "base_django.html",
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
|
nautobot/core/filters.py
CHANGED
|
@@ -12,7 +12,6 @@ from django_filters.constants import EMPTY_VALUES
|
|
|
12
12
|
from django_filters.utils import get_model_field, resolve_field
|
|
13
13
|
from drf_spectacular.types import OpenApiTypes
|
|
14
14
|
from drf_spectacular.utils import extend_schema_field
|
|
15
|
-
from taggit.managers import TaggableManager
|
|
16
15
|
|
|
17
16
|
from nautobot.core import constants, forms
|
|
18
17
|
from nautobot.core.forms import widgets
|
|
@@ -557,7 +556,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
557
556
|
models.URLField: {"filter_class": MultiValueCharFilter},
|
|
558
557
|
models.UUIDField: {"filter_class": MultiValueUUIDFilter},
|
|
559
558
|
core_fields.MACAddressCharField: {"filter_class": MultiValueMACAddressFilter},
|
|
560
|
-
|
|
559
|
+
core_fields.TagsField: {"filter_class": TagFilter},
|
|
561
560
|
}
|
|
562
561
|
)
|
|
563
562
|
|
|
@@ -763,4 +762,5 @@ class NameSlugSearchFilterSet(django_filters.FilterSet):
|
|
|
763
762
|
A base class for adding the search method to models which only expose the `name` and `slug` fields
|
|
764
763
|
"""
|
|
765
764
|
|
|
765
|
+
# TODO Modify and rename this class after slugs are removed from all models.
|
|
766
766
|
q = SearchFilter(filter_predicates={"name": "icontains", "slug": "icontains"})
|
nautobot/core/forms/__init__.py
CHANGED
|
@@ -52,10 +52,8 @@ from nautobot.core.forms.utils import (
|
|
|
52
52
|
expand_ipaddress_pattern,
|
|
53
53
|
form_from_model,
|
|
54
54
|
parse_alphanumeric_range,
|
|
55
|
-
parse_csv,
|
|
56
55
|
parse_numeric_range,
|
|
57
56
|
restrict_form_fields,
|
|
58
|
-
validate_csv,
|
|
59
57
|
)
|
|
60
58
|
from nautobot.core.forms.widgets import (
|
|
61
59
|
APISelect,
|
|
@@ -125,7 +123,6 @@ __all__ = (
|
|
|
125
123
|
"NUMERIC_EXPANSION_PATTERN",
|
|
126
124
|
"NumericArrayField",
|
|
127
125
|
"parse_alphanumeric_range",
|
|
128
|
-
"parse_csv",
|
|
129
126
|
"parse_numeric_range",
|
|
130
127
|
"PrefixFieldMixin",
|
|
131
128
|
"restrict_form_fields",
|
|
@@ -141,5 +138,4 @@ __all__ = (
|
|
|
141
138
|
"TableConfigForm",
|
|
142
139
|
"TagFilterField",
|
|
143
140
|
"TimePicker",
|
|
144
|
-
"validate_csv",
|
|
145
141
|
)
|
nautobot/core/forms/fields.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import csv
|
|
2
|
-
from io import StringIO
|
|
3
1
|
import json
|
|
4
2
|
import re
|
|
5
3
|
|
|
@@ -50,20 +48,22 @@ __all__ = (
|
|
|
50
48
|
|
|
51
49
|
class CSVDataField(django_forms.CharField):
|
|
52
50
|
"""
|
|
53
|
-
A CharField (rendered as a Textarea) which
|
|
54
|
-
item is a dictionary of column headers, mapping field names to the attribute by which they match a related object
|
|
55
|
-
(where applicable). The second item is a list of dictionaries, each representing a discrete row of CSV data.
|
|
51
|
+
A CharField (rendered as a Textarea) which expects CSV-formatted data.
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
Initial value is a list of headers corresponding to the required fields for the given serializer class.
|
|
54
|
+
|
|
55
|
+
This no longer actually does any CSV parsing or validation on its own,
|
|
56
|
+
as that is now handled by the NautobotCSVParser class and the REST API serializers.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
required_field_names: List of field names representing required fields for this import.
|
|
58
60
|
"""
|
|
59
61
|
|
|
60
62
|
widget = django_forms.Textarea
|
|
61
63
|
|
|
62
|
-
def __init__(self,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.fields = form.fields
|
|
66
|
-
self.required_fields = [name for name, field in form.fields.items() if field.required]
|
|
64
|
+
def __init__(self, *args, required_field_names="", **kwargs):
|
|
65
|
+
self.required_field_names = required_field_names
|
|
66
|
+
kwargs.setdefault("required", False)
|
|
67
67
|
|
|
68
68
|
super().__init__(*args, **kwargs)
|
|
69
69
|
|
|
@@ -71,7 +71,7 @@ class CSVDataField(django_forms.CharField):
|
|
|
71
71
|
if not self.label:
|
|
72
72
|
self.label = ""
|
|
73
73
|
if not self.initial:
|
|
74
|
-
self.initial = ",".join(self.
|
|
74
|
+
self.initial = ",".join(self.required_field_names) + "\n"
|
|
75
75
|
if not self.help_text:
|
|
76
76
|
self.help_text = (
|
|
77
77
|
"Enter the list of column headers followed by one line per record to be imported, using "
|
|
@@ -79,36 +79,17 @@ class CSVDataField(django_forms.CharField):
|
|
|
79
79
|
"in double quotes."
|
|
80
80
|
)
|
|
81
81
|
|
|
82
|
-
def to_python(self, value):
|
|
83
|
-
if value is None:
|
|
84
|
-
return None
|
|
85
|
-
reader = csv.reader(StringIO(value.strip()))
|
|
86
|
-
return forms.parse_csv(reader)
|
|
87
|
-
|
|
88
|
-
def validate(self, value):
|
|
89
|
-
if value is None:
|
|
90
|
-
return None
|
|
91
|
-
headers, _records = value
|
|
92
|
-
forms.validate_csv(headers, self.fields, self.required_fields)
|
|
93
|
-
|
|
94
|
-
return value
|
|
95
|
-
|
|
96
82
|
|
|
97
83
|
class CSVFileField(django_forms.FileField):
|
|
98
84
|
"""
|
|
99
|
-
A FileField (rendered as a ClearableFileInput) which
|
|
100
|
-
data as a two-tuple: The first item is a dictionary of column headers, mapping field names to the attribute
|
|
101
|
-
by which they match a related object (where applicable). The second item is a list of dictionaries, each
|
|
102
|
-
representing a discrete row of CSV data.
|
|
85
|
+
A FileField (rendered as a ClearableFileInput) which expects a file containing CSV-formatted data.
|
|
103
86
|
|
|
104
|
-
|
|
87
|
+
This no longer actually does any CSV parsing or validation on its own,
|
|
88
|
+
as that is now handled by the NautobotCSVParser class and the REST API serializers.
|
|
105
89
|
"""
|
|
106
90
|
|
|
107
|
-
def __init__(self,
|
|
108
|
-
|
|
109
|
-
self.model = form.Meta.model
|
|
110
|
-
self.fields = form.fields
|
|
111
|
-
self.required_fields = [name for name, field in form.fields.items() if field.required]
|
|
91
|
+
def __init__(self, *args, **kwargs):
|
|
92
|
+
kwargs.setdefault("required", False)
|
|
112
93
|
|
|
113
94
|
super().__init__(*args, **kwargs)
|
|
114
95
|
|
|
@@ -122,37 +103,19 @@ class CSVFileField(django_forms.FileField):
|
|
|
122
103
|
)
|
|
123
104
|
|
|
124
105
|
def to_python(self, file):
|
|
106
|
+
"""For parity with CSVDataField, this returns the CSV text rather than an UploadedFile object."""
|
|
125
107
|
if file is None:
|
|
126
108
|
return None
|
|
127
109
|
|
|
128
110
|
file = super().to_python(file)
|
|
129
|
-
|
|
130
|
-
# Check if there is only one column of input
|
|
131
|
-
# If so a delimiter cannot be determined and it will raise an exception.
|
|
132
|
-
# In that case we will use csv.excel class
|
|
133
|
-
# Which defines the usual properties of an Excel-generated CSV file.
|
|
134
|
-
try:
|
|
135
|
-
dialect = csv.Sniffer().sniff(csv_str, delimiters=",")
|
|
136
|
-
except csv.Error:
|
|
137
|
-
dialect = csv.excel
|
|
138
|
-
reader = csv.reader(csv_str.splitlines(), dialect)
|
|
139
|
-
headers, records = forms.parse_csv(reader)
|
|
140
|
-
|
|
141
|
-
return headers, records
|
|
142
|
-
|
|
143
|
-
def validate(self, value):
|
|
144
|
-
if value is None:
|
|
145
|
-
return None
|
|
146
|
-
|
|
147
|
-
headers, _records = value
|
|
148
|
-
forms.validate_csv(headers, self.fields, self.required_fields)
|
|
149
|
-
|
|
150
|
-
return value
|
|
111
|
+
return file.read().decode("utf-8-sig").strip()
|
|
151
112
|
|
|
152
113
|
|
|
153
114
|
class CSVChoiceField(django_forms.ChoiceField):
|
|
154
115
|
"""
|
|
155
116
|
Invert the provided set of choices to take the human-friendly label as input, and return the database value.
|
|
117
|
+
|
|
118
|
+
Despite the name, this is no longer used in CSV imports since 2.0, but *is* used in JSON/YAML import of DeviceTypes.
|
|
156
119
|
"""
|
|
157
120
|
|
|
158
121
|
STATIC_CHOICES = True
|
|
@@ -164,7 +127,10 @@ class CSVChoiceField(django_forms.ChoiceField):
|
|
|
164
127
|
|
|
165
128
|
class CSVMultipleChoiceField(CSVChoiceField):
|
|
166
129
|
"""
|
|
167
|
-
A version of CSVChoiceField that supports and emits a list of choice values
|
|
130
|
+
A version of CSVChoiceField that supports and emits a list of choice values.
|
|
131
|
+
|
|
132
|
+
As with CSVChoiceField, the name is misleading, as this is no longer used for CSV imports, but is used for
|
|
133
|
+
JSON/YAML import of DeviceTypes still.
|
|
168
134
|
"""
|
|
169
135
|
|
|
170
136
|
def to_python(self, value):
|
|
@@ -182,6 +148,9 @@ class CSVMultipleChoiceField(CSVChoiceField):
|
|
|
182
148
|
class CSVModelChoiceField(django_forms.ModelChoiceField):
|
|
183
149
|
"""
|
|
184
150
|
Provides additional validation for model choices entered as CSV data.
|
|
151
|
+
|
|
152
|
+
Note: class name is misleading; the subclass CSVContentTypeField (below) is also used in FilterSets, where it has
|
|
153
|
+
nothing to do with CSV data.
|
|
185
154
|
"""
|
|
186
155
|
|
|
187
156
|
default_error_messages = {
|
|
@@ -198,6 +167,8 @@ class CSVModelChoiceField(django_forms.ModelChoiceField):
|
|
|
198
167
|
class CSVContentTypeField(CSVModelChoiceField):
|
|
199
168
|
"""
|
|
200
169
|
Reference a ContentType in the form `{app_label}.{model}`.
|
|
170
|
+
|
|
171
|
+
Note: class name is misleading; this field is also used in numerous FilterSets where it has nothing to do with CSV.
|
|
201
172
|
"""
|
|
202
173
|
|
|
203
174
|
STATIC_CHOICES = True
|
|
@@ -313,6 +284,9 @@ class MultiValueCharField(django_forms.CharField):
|
|
|
313
284
|
class CSVMultipleContentTypeField(MultipleContentTypeField):
|
|
314
285
|
"""
|
|
315
286
|
Reference a list of `ContentType` objects in the form `{app_label}.{model}'.
|
|
287
|
+
|
|
288
|
+
Note: This is unused in Nautobot core at this time, but some apps (data-validation-engine) use this for non-CSV
|
|
289
|
+
purposes, similar to CSVContentTypeField above.
|
|
316
290
|
"""
|
|
317
291
|
|
|
318
292
|
def prepare_value(self, value):
|
|
@@ -483,7 +457,7 @@ class DynamicModelChoiceMixin:
|
|
|
483
457
|
:param null_option: The string used to represent a null selection (if any)
|
|
484
458
|
:param disabled_indicator: The name of the field which, if populated, will disable selection of the
|
|
485
459
|
choice (optional)
|
|
486
|
-
:param
|
|
460
|
+
:param depth: Nested serialization depth when making API requests (default: `0` or a flat representation)
|
|
487
461
|
"""
|
|
488
462
|
|
|
489
463
|
filter = django_filters.ModelChoiceFilter # 2.0 TODO(Glenn): can we rename this? pylint: disable=redefined-builtin
|
|
@@ -496,7 +470,7 @@ class DynamicModelChoiceMixin:
|
|
|
496
470
|
initial_params=None,
|
|
497
471
|
null_option=None,
|
|
498
472
|
disabled_indicator=None,
|
|
499
|
-
|
|
473
|
+
depth=0,
|
|
500
474
|
*args,
|
|
501
475
|
**kwargs,
|
|
502
476
|
):
|
|
@@ -505,7 +479,7 @@ class DynamicModelChoiceMixin:
|
|
|
505
479
|
self.initial_params = initial_params or {}
|
|
506
480
|
self.null_option = null_option
|
|
507
481
|
self.disabled_indicator = disabled_indicator
|
|
508
|
-
self.
|
|
482
|
+
self.depth = depth
|
|
509
483
|
|
|
510
484
|
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
|
|
511
485
|
# by widget_attrs()
|
|
@@ -530,9 +504,8 @@ class DynamicModelChoiceMixin:
|
|
|
530
504
|
if self.disabled_indicator is not None:
|
|
531
505
|
attrs["disabled-indicator"] = self.disabled_indicator
|
|
532
506
|
|
|
533
|
-
# Toggle
|
|
534
|
-
|
|
535
|
-
attrs["data-full"] = "true"
|
|
507
|
+
# Toggle depth
|
|
508
|
+
attrs["data-depth"] = self.depth
|
|
536
509
|
|
|
537
510
|
# Attach any static query parameters
|
|
538
511
|
for key, value in self.query_params.items():
|
nautobot/core/forms/forms.py
CHANGED
|
@@ -137,7 +137,10 @@ class BulkRenameForm(forms.Form):
|
|
|
137
137
|
|
|
138
138
|
class CSVModelForm(forms.ModelForm):
|
|
139
139
|
"""
|
|
140
|
-
ModelForm used for the import of objects
|
|
140
|
+
ModelForm used for the import of objects.
|
|
141
|
+
|
|
142
|
+
Note: the name is misleading as since 2.0 this is no longer used for CSV imports; however it *is* still used for
|
|
143
|
+
JSON/YAML imports of DeviceTypes and their component templates.
|
|
141
144
|
"""
|
|
142
145
|
|
|
143
146
|
def __init__(self, *args, headers=None, **kwargs):
|
nautobot/core/forms/utils.py
CHANGED
|
@@ -15,8 +15,6 @@ __all__ = (
|
|
|
15
15
|
"parse_alphanumeric_range",
|
|
16
16
|
"parse_numeric_range",
|
|
17
17
|
"restrict_form_fields",
|
|
18
|
-
"parse_csv",
|
|
19
|
-
"validate_csv",
|
|
20
18
|
)
|
|
21
19
|
|
|
22
20
|
|
|
@@ -139,56 +137,6 @@ def restrict_form_fields(form, user, action="view"):
|
|
|
139
137
|
field.queryset = field.queryset.restrict(user, action)
|
|
140
138
|
|
|
141
139
|
|
|
142
|
-
def parse_csv(reader):
|
|
143
|
-
"""
|
|
144
|
-
Parse a csv_reader object into a headers dictionary and a list of records dictionaries. Raise an error
|
|
145
|
-
if the records are formatted incorrectly. Return headers and records as a tuple.
|
|
146
|
-
"""
|
|
147
|
-
records = []
|
|
148
|
-
headers = {}
|
|
149
|
-
|
|
150
|
-
# Consume the first line of CSV data as column headers. Create a dictionary mapping each header to an optional
|
|
151
|
-
# "to" field specifying how the related object is being referenced. For example, importing a Device might use a
|
|
152
|
-
# `site.slug` header, to indicate the related site is being referenced by its slug.
|
|
153
|
-
|
|
154
|
-
for header in next(reader):
|
|
155
|
-
if "." in header:
|
|
156
|
-
field, to_field = header.split(".", 1)
|
|
157
|
-
headers[field] = to_field
|
|
158
|
-
else:
|
|
159
|
-
headers[header] = None
|
|
160
|
-
|
|
161
|
-
# Parse CSV rows into a list of dictionaries mapped from the column headers.
|
|
162
|
-
for i, row in enumerate(reader, start=1):
|
|
163
|
-
if len(row) != len(headers):
|
|
164
|
-
raise django_forms.ValidationError(f"Row {i}: Expected {len(headers)} columns but found {len(row)}")
|
|
165
|
-
row = [col.strip() for col in row]
|
|
166
|
-
record = dict(zip(headers.keys(), row))
|
|
167
|
-
records.append(record)
|
|
168
|
-
|
|
169
|
-
return headers, records
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def validate_csv(headers, fields, required_fields):
|
|
173
|
-
"""
|
|
174
|
-
Validate that parsed csv data conforms to the object's available fields. Raise validation errors
|
|
175
|
-
if parsed csv data contains invalid headers or does not contain required headers.
|
|
176
|
-
"""
|
|
177
|
-
# Validate provided column headers
|
|
178
|
-
for field, to_field in headers.items():
|
|
179
|
-
if field not in fields:
|
|
180
|
-
raise django_forms.ValidationError(f'Unexpected column header "{field}" found.')
|
|
181
|
-
if to_field and not hasattr(fields[field], "to_field_name"):
|
|
182
|
-
raise django_forms.ValidationError(f'Column "{field}" is not a related object; cannot use dots')
|
|
183
|
-
if to_field and not hasattr(fields[field].queryset.model, to_field):
|
|
184
|
-
raise django_forms.ValidationError(f'Invalid related object attribute for column "{field}": {to_field}')
|
|
185
|
-
|
|
186
|
-
# Validate required fields
|
|
187
|
-
for f in required_fields:
|
|
188
|
-
if f not in headers:
|
|
189
|
-
raise django_forms.ValidationError(f'Required column header "{f}" not found.')
|
|
190
|
-
|
|
191
|
-
|
|
192
140
|
def add_field_to_filter_form_class(form_class, field_name, field_obj):
|
|
193
141
|
"""
|
|
194
142
|
Attach a field to an existing filter form class.
|
nautobot/core/graphql/schema.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Schema module for GraphQL."""
|
|
2
2
|
from collections import OrderedDict
|
|
3
3
|
import logging
|
|
4
|
-
import warnings
|
|
5
4
|
|
|
6
5
|
from django.conf import settings
|
|
7
6
|
from django.contrib.contenttypes.models import ContentType
|
|
@@ -276,18 +275,7 @@ def extend_schema_type_computed_field(schema_type, model):
|
|
|
276
275
|
prefix = f"{settings.GRAPHQL_COMPUTED_FIELD_PREFIX}_"
|
|
277
276
|
|
|
278
277
|
for field in cfs:
|
|
279
|
-
field_name = f"{prefix}{
|
|
280
|
-
if str_to_var_name(field.slug) != field.slug:
|
|
281
|
-
# 2.0 TODO: str_to_var_name is lossy, it may cause different fields to map to the same field_name
|
|
282
|
-
# In 2.0 we should simply omit fields whose slugs are invalid in GraphQL, instead of mapping them.
|
|
283
|
-
# We need to make sure that slug/key is unique in a data migration before we remove the warning
|
|
284
|
-
# See https://github.com/nautobot/nautobot/pull/3426 for detailed solution
|
|
285
|
-
warnings.warn(
|
|
286
|
-
f'Computed field "{field}" on {model._meta.verbose_name} does not have a GraphQL-safe slug '
|
|
287
|
-
f'("{field.slug}"); for now it will be mapped to the GraphQL name "{field_name}", '
|
|
288
|
-
"but in a future release this field may fail to appear in GraphQL.",
|
|
289
|
-
FutureWarning,
|
|
290
|
-
)
|
|
278
|
+
field_name = f"{prefix}{field.key}"
|
|
291
279
|
resolver_name = f"resolve_{field_name}"
|
|
292
280
|
|
|
293
281
|
if hasattr(schema_type, resolver_name):
|
|
@@ -303,7 +291,7 @@ def extend_schema_type_computed_field(schema_type, model):
|
|
|
303
291
|
setattr(
|
|
304
292
|
schema_type,
|
|
305
293
|
resolver_name,
|
|
306
|
-
generate_computed_field_resolver(field.
|
|
294
|
+
generate_computed_field_resolver(field.key, resolver_name),
|
|
307
295
|
)
|
|
308
296
|
|
|
309
297
|
schema_type._meta.fields[field_name] = graphene.Field.mounted(graphene.String())
|
|
@@ -376,24 +364,13 @@ def extend_schema_type_relationships(schema_type, model):
|
|
|
376
364
|
for relationship in relationships:
|
|
377
365
|
peer_side = RelationshipSideChoices.OPPOSITE[side]
|
|
378
366
|
|
|
379
|
-
# Generate the name of the attribute and the name of the resolver based on the
|
|
367
|
+
# Generate the name of the attribute and the name of the resolver based on the key of the relationship
|
|
380
368
|
# and based on the prefix
|
|
381
|
-
rel_name = f"{prefix}{
|
|
369
|
+
rel_name = f"{prefix}{relationship.key}"
|
|
382
370
|
# Handle non-symmetric relationships where the model can be either source or destination
|
|
383
371
|
if not relationship.symmetric and relationship.source_type == relationship.destination_type:
|
|
384
372
|
rel_name = f"{rel_name}_{peer_side}"
|
|
385
373
|
resolver_name = f"resolve_{rel_name}"
|
|
386
|
-
if str_to_var_name(relationship.slug) != relationship.slug:
|
|
387
|
-
# 2.0 TODO: str_to_var_name is lossy, it may cause different relationships to map to the same rel_name
|
|
388
|
-
# In 2.0 we should simply omit relations whose slugs are invalid in GraphQL, instead of mapping them.
|
|
389
|
-
# We need to make sure that slug/key is unique in a data migration before we remove the warning
|
|
390
|
-
# See https://github.com/nautobot/nautobot/pull/3426 for detailed solution
|
|
391
|
-
warnings.warn(
|
|
392
|
-
f'Relationship "{relationship}" on {model._meta.verbose_name} does not have a GraphQL-safe slug '
|
|
393
|
-
f'("{relationship.slug}"); for now it will be mapped to the GraphQL name "{rel_name}", '
|
|
394
|
-
"but in a future release this relationship may fail to appear in GraphQL.",
|
|
395
|
-
FutureWarning,
|
|
396
|
-
)
|
|
397
374
|
|
|
398
375
|
if hasattr(schema_type, resolver_name):
|
|
399
376
|
# If a symmetric relationship, and this is destination side, we already added source side, expected
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from nautobot.core.celery import app, register_jobs
|
|
2
|
+
from nautobot.extras.choices import LogLevelChoices
|
|
3
|
+
from nautobot.extras.datasources import ensure_git_repository, git_repository_dry_run, refresh_datasource_content
|
|
4
|
+
from nautobot.extras.jobs import Job, ObjectVar
|
|
5
|
+
from nautobot.extras.models import GitRepository
|
|
6
|
+
|
|
7
|
+
name = "System Jobs"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitRepositorySync(Job):
|
|
11
|
+
"""
|
|
12
|
+
System job to clone and/or pull a Git repository, then invoke `refresh_datasource_content()`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
repository = ObjectVar(
|
|
16
|
+
description="Git Repository to pull and refresh",
|
|
17
|
+
label="Git Repository",
|
|
18
|
+
model=GitRepository,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
class Meta:
|
|
22
|
+
name = "Git Repository: Sync"
|
|
23
|
+
has_sensitive_variables = False
|
|
24
|
+
|
|
25
|
+
def run(self, repository):
|
|
26
|
+
job_result = self.job_result
|
|
27
|
+
user = job_result.user
|
|
28
|
+
|
|
29
|
+
job_result.log(
|
|
30
|
+
f'Creating/refreshing local copy of Git repository "{repository.name}"...',
|
|
31
|
+
logger=self.logger,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
ensure_git_repository(repository, job_result=job_result, logger=self.logger)
|
|
36
|
+
refresh_datasource_content("extras.gitrepository", repository, user, job_result, delete=False)
|
|
37
|
+
# Given that the above succeeded, tell all workers (including ourself) to call ensure_git_repository()
|
|
38
|
+
app.control.broadcast("refresh_git_repository", repository_pk=repository.pk, head=repository.current_head)
|
|
39
|
+
finally:
|
|
40
|
+
job_result.log(
|
|
41
|
+
f"Repository synchronization completed in {job_result.duration}",
|
|
42
|
+
level_choice=LogLevelChoices.LOG_INFO,
|
|
43
|
+
logger=self.logger,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class GitRepositoryDryRun(Job):
|
|
48
|
+
"""System Job to perform a dry run on a Git repository."""
|
|
49
|
+
|
|
50
|
+
repository = ObjectVar(
|
|
51
|
+
description="Git Repository to dry-run",
|
|
52
|
+
label="Git Repository",
|
|
53
|
+
model=GitRepository,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
class Meta:
|
|
57
|
+
name = "Git Repository: Dry-Run"
|
|
58
|
+
has_sensitive_variables = False
|
|
59
|
+
|
|
60
|
+
def run(self, repository):
|
|
61
|
+
job_result = self.job_result
|
|
62
|
+
job_result.log(f'Performing a Dry Run on Git repository "{repository.name}"...', logger=self.logger)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
git_repository_dry_run(repository, job_result=job_result, logger=self.logger)
|
|
66
|
+
finally:
|
|
67
|
+
job_result.log(
|
|
68
|
+
f"Repository dry run completed in {job_result.duration}",
|
|
69
|
+
level_choice=LogLevelChoices.LOG_INFO,
|
|
70
|
+
logger=self.logger,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
jobs = [GitRepositorySync, GitRepositoryDryRun]
|
|
75
|
+
register_jobs(*jobs)
|