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
nautobot/core/apps/__init__.py
CHANGED
|
@@ -9,18 +9,20 @@ from django.db.models import JSONField, BigIntegerField, BinaryField
|
|
|
9
9
|
from django.db.models.signals import post_migrate
|
|
10
10
|
from django.urls import reverse
|
|
11
11
|
from django.urls.exceptions import NoReverseMatch
|
|
12
|
+
from django.utils.module_loading import import_string
|
|
12
13
|
|
|
13
14
|
from constance.apps import ConstanceConfig
|
|
14
15
|
from graphene.types import generic, String
|
|
15
16
|
|
|
16
|
-
from nautobot.core.choices import ButtonActionColorChoices, ButtonActionIconChoices
|
|
17
17
|
from nautobot.core.signals import nautobot_database_ready
|
|
18
|
-
from nautobot.extras.plugins.utils import import_object
|
|
19
18
|
from nautobot.extras.registry import registry
|
|
20
19
|
|
|
21
20
|
|
|
21
|
+
MENU_TABS = ("Inventory", "Networks", "Security", "Automation", "Platform")
|
|
22
|
+
|
|
23
|
+
|
|
22
24
|
logger = logging.getLogger(__name__)
|
|
23
|
-
registry["nav_menu"] = {"
|
|
25
|
+
registry["nav_menu"] = dict({tab: {"groups": {}, "permissions": set()} for tab in MENU_TABS})
|
|
24
26
|
registry["homepage_layout"] = {"panels": {}}
|
|
25
27
|
|
|
26
28
|
|
|
@@ -42,13 +44,17 @@ class NautobotConfig(AppConfig):
|
|
|
42
44
|
"""
|
|
43
45
|
Ready function initiates the import application.
|
|
44
46
|
"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
try:
|
|
48
|
+
homepage_layout = import_string(f"{self.name}.{self.homepage_layout}")
|
|
47
49
|
register_homepage_panels(self.path, self.label, homepage_layout)
|
|
50
|
+
except ModuleNotFoundError:
|
|
51
|
+
pass
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
try:
|
|
54
|
+
menu_items = import_string(f"{self.name}.{self.menu_tabs}")
|
|
51
55
|
register_menu_items(menu_items)
|
|
56
|
+
except ModuleNotFoundError:
|
|
57
|
+
pass
|
|
52
58
|
|
|
53
59
|
|
|
54
60
|
def create_or_check_entry(grouping, record, key, path):
|
|
@@ -56,82 +62,86 @@ def create_or_check_entry(grouping, record, key, path):
|
|
|
56
62
|
grouping[key] = record.initial_dict
|
|
57
63
|
else:
|
|
58
64
|
for attr, value in record.fixed_fields:
|
|
59
|
-
if grouping[key][attr]:
|
|
65
|
+
if grouping[key][attr] != value:
|
|
60
66
|
logger.error("Unable to redefine %s on %s from %s to %s", attr, path, grouping[key][attr], value)
|
|
61
67
|
|
|
62
68
|
|
|
63
69
|
def register_menu_items(tab_list):
|
|
64
70
|
"""
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
Create or update the `registry["nav_menu"]` dictionary with the provided objects to define the nav bar.
|
|
72
|
+
|
|
73
|
+
The dictionary is built from three key objects, NavMenuTab, NavMenuGroup (which may be nested, once),
|
|
74
|
+
and NavMenuItem.
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
NavMenuButton. The Django template then uses this dictionary to generate the navbar HTML.
|
|
76
|
+
This dictionary is then presented via the REST API to the Nautobot UI frontend.
|
|
70
77
|
"""
|
|
71
78
|
for nav_tab in tab_list:
|
|
72
|
-
if isinstance(nav_tab, NavMenuTab):
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
79
|
+
if not isinstance(nav_tab, NavMenuTab):
|
|
80
|
+
raise TypeError(f"Top level objects need to be an instance of NavMenuTab: {nav_tab}")
|
|
81
|
+
if nav_tab.name not in MENU_TABS:
|
|
82
|
+
raise ValueError(f"Unexpected NavMenuTab name: {nav_tab.name}")
|
|
83
|
+
|
|
84
|
+
tab_perms = registry["nav_menu"][nav_tab.name]["permissions"]
|
|
85
|
+
registry_groups = registry["nav_menu"][nav_tab.name]["groups"]
|
|
86
|
+
# TODO: allow for recursive (more than two-level) nesting of groups?
|
|
87
|
+
for group in nav_tab.groups:
|
|
88
|
+
if not isinstance(group, NavMenuGroup):
|
|
89
|
+
raise TypeError(f"Expected a NavMenuGroup, but got {group}")
|
|
90
|
+
|
|
91
|
+
create_or_check_entry(registry_groups, group, group.name, f"{nav_tab.name} -> {group.name}")
|
|
92
|
+
|
|
93
|
+
group_perms = registry_groups[group.name]["permissions"]
|
|
94
|
+
for item in group.items:
|
|
95
|
+
if not isinstance(item, (NavMenuGroup, NavMenuItem)):
|
|
96
|
+
raise TypeError(f"Expected NavMenuItem or NavMenuGroup, but found {item}")
|
|
97
|
+
create_or_check_entry(
|
|
98
|
+
registry_groups[group.name]["items"],
|
|
99
|
+
item,
|
|
100
|
+
item.name,
|
|
101
|
+
f"{nav_tab.name} -> {group.name} -> {item.name}",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
item_perms = registry_groups[group.name]["items"][item.name]["permissions"]
|
|
105
|
+
if isinstance(item, NavMenuGroup):
|
|
106
|
+
for inner_item in item.items:
|
|
107
|
+
if not isinstance(inner_item, NavMenuItem):
|
|
108
|
+
raise TypeError(f"Expected a NavMenuItem, but found {inner_item}")
|
|
96
109
|
|
|
97
|
-
registry_buttons = registry_groups[group.name]["items"][item.link]["buttons"]
|
|
98
|
-
for button in item.buttons:
|
|
99
110
|
create_or_check_entry(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
f"{nav_tab.name} -> {group.name} -> {item.
|
|
111
|
+
registry_groups[group.name]["items"][item.name]["items"],
|
|
112
|
+
inner_item,
|
|
113
|
+
inner_item.name,
|
|
114
|
+
f"{nav_tab.name} -> {group.name} -> {item.name} -> {inner_item.name}",
|
|
104
115
|
)
|
|
116
|
+
item_perms |= inner_item.permissions
|
|
105
117
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
registry_groups[group.name]["items"][item.name]["items"] = OrderedDict(
|
|
119
|
+
sorted(
|
|
120
|
+
registry_groups[group.name]["items"][item.name]["items"].items(),
|
|
121
|
+
key=lambda kv_pair: kv_pair[1]["weight"],
|
|
122
|
+
)
|
|
109
123
|
)
|
|
110
124
|
|
|
111
|
-
group_perms |= set(perms for perms in item.permissions)
|
|
112
|
-
|
|
113
|
-
# Add sorted items to group registry dict
|
|
114
|
-
registry_groups[group.name]["items"] = OrderedDict(
|
|
115
|
-
sorted(registry_groups[group.name]["items"].items(), key=lambda kv_pair: kv_pair[1]["weight"])
|
|
116
|
-
)
|
|
117
125
|
# Add collected permissions to group
|
|
118
|
-
registry_groups[group.name]["permissions"] =
|
|
119
|
-
# Add collected permissions to tab
|
|
120
|
-
tab_perms |= group_perms
|
|
126
|
+
registry_groups[group.name]["items"][item.name]["permissions"] = item_perms
|
|
121
127
|
|
|
122
|
-
|
|
123
|
-
registry["nav_menu"]["tabs"][nav_tab.name]["groups"] = OrderedDict(
|
|
124
|
-
sorted(registry_groups.items(), key=lambda kv_pair: kv_pair[1]["weight"])
|
|
125
|
-
)
|
|
126
|
-
# Add collected permissions to tab dict
|
|
127
|
-
registry["nav_menu"]["tabs"][nav_tab.name]["permissions"] |= tab_perms
|
|
128
|
-
else:
|
|
129
|
-
raise TypeError(f"Top level objects need to be an instance of NavMenuTab: {nav_tab}")
|
|
128
|
+
group_perms |= item_perms
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
# Add sorted items to group registry dict
|
|
131
|
+
registry_groups[group.name]["items"] = OrderedDict(
|
|
132
|
+
sorted(registry_groups[group.name]["items"].items(), key=lambda kv_pair: kv_pair[1]["weight"])
|
|
133
|
+
)
|
|
134
|
+
# Add collected permissions to group
|
|
135
|
+
registry_groups[group.name]["permissions"] = group_perms
|
|
136
|
+
# Add collected permissions to tab
|
|
137
|
+
tab_perms |= group_perms
|
|
138
|
+
|
|
139
|
+
# Add sorted groups to tab dict
|
|
140
|
+
registry["nav_menu"][nav_tab.name]["groups"] = OrderedDict(
|
|
141
|
+
sorted(registry_groups.items(), key=lambda kv_pair: kv_pair[1]["weight"])
|
|
134
142
|
)
|
|
143
|
+
# Add collected permissions to tab dict
|
|
144
|
+
registry["nav_menu"][nav_tab.name]["permissions"] |= tab_perms
|
|
135
145
|
|
|
136
146
|
|
|
137
147
|
def register_homepage_panels(path, label, homepage_layout):
|
|
@@ -230,12 +240,14 @@ class NavMenuBase(ABC): # replaces PermissionsMixin
|
|
|
230
240
|
|
|
231
241
|
@property
|
|
232
242
|
@abstractmethod
|
|
233
|
-
def initial_dict(self): # to be implemented by each subclass
|
|
243
|
+
def initial_dict(self) -> dict: # to be implemented by each subclass
|
|
244
|
+
"""Attributes to be stored when adding this item to the nav menu data for the first time."""
|
|
234
245
|
return {}
|
|
235
246
|
|
|
236
247
|
@property
|
|
237
248
|
@abstractmethod
|
|
238
|
-
def fixed_fields(self): # to be implemented by subclass
|
|
249
|
+
def fixed_fields(self) -> tuple: # to be implemented by subclass
|
|
250
|
+
"""Tuple of (name, attribute) entries describing fields that may not be altered after declaration."""
|
|
239
251
|
return ()
|
|
240
252
|
|
|
241
253
|
|
|
@@ -246,14 +258,13 @@ class PermissionsMixin:
|
|
|
246
258
|
"""Ensure permissions."""
|
|
247
259
|
if permissions is not None and not isinstance(permissions, (list, tuple)):
|
|
248
260
|
raise TypeError("Permissions must be passed as a tuple or list.")
|
|
249
|
-
self.permissions = permissions
|
|
261
|
+
self.permissions = set(permissions) if permissions else set()
|
|
250
262
|
|
|
251
263
|
|
|
252
264
|
class HomePagePanel(HomePageBase, PermissionsMixin):
|
|
253
265
|
"""Defines properties that can be used for a panel."""
|
|
254
266
|
|
|
255
|
-
|
|
256
|
-
items = []
|
|
267
|
+
items = None
|
|
257
268
|
template_path = None
|
|
258
269
|
|
|
259
270
|
@property
|
|
@@ -283,13 +294,10 @@ class HomePagePanel(HomePageBase, PermissionsMixin):
|
|
|
283
294
|
items (list): List of items to be rendered in this panel.
|
|
284
295
|
weight (int): The weight of this panel.
|
|
285
296
|
"""
|
|
286
|
-
if permissions is None:
|
|
287
|
-
permissions = []
|
|
288
297
|
super().__init__(permissions)
|
|
289
298
|
self.custom_data = custom_data
|
|
290
299
|
self.custom_template = custom_template
|
|
291
300
|
self.name = name
|
|
292
|
-
self.permissions = permissions
|
|
293
301
|
self.weight = weight
|
|
294
302
|
|
|
295
303
|
if items is not None and custom_template is not None:
|
|
@@ -300,19 +308,20 @@ class HomePagePanel(HomePageBase, PermissionsMixin):
|
|
|
300
308
|
elif not all(isinstance(item, (HomePageGroup, HomePageItem)) for item in items):
|
|
301
309
|
raise TypeError("All items defined in a panel must be an instance of HomePageGroup or HomePageItem")
|
|
302
310
|
self.items = items
|
|
311
|
+
else:
|
|
312
|
+
self.items = []
|
|
303
313
|
|
|
304
314
|
|
|
305
315
|
class HomePageGroup(HomePageBase, PermissionsMixin):
|
|
306
316
|
"""Defines properties that can be used for a panel group."""
|
|
307
317
|
|
|
308
|
-
permissions = []
|
|
309
318
|
items = []
|
|
310
319
|
|
|
311
320
|
@property
|
|
312
321
|
def initial_dict(self):
|
|
313
322
|
return {
|
|
314
323
|
"items": {},
|
|
315
|
-
"permissions":
|
|
324
|
+
"permissions": self.permissions,
|
|
316
325
|
"weight": self.weight,
|
|
317
326
|
}
|
|
318
327
|
|
|
@@ -330,8 +339,6 @@ class HomePageGroup(HomePageBase, PermissionsMixin):
|
|
|
330
339
|
items (list): List of items to be rendered in this group.
|
|
331
340
|
weight (int): The weight of this group.
|
|
332
341
|
"""
|
|
333
|
-
if permissions is None:
|
|
334
|
-
permissions = []
|
|
335
342
|
super().__init__(permissions)
|
|
336
343
|
self.name = name
|
|
337
344
|
self.weight = weight
|
|
@@ -347,7 +354,6 @@ class HomePageGroup(HomePageBase, PermissionsMixin):
|
|
|
347
354
|
class HomePageItem(HomePageBase, PermissionsMixin):
|
|
348
355
|
"""Defines properties that can be used for a panel item."""
|
|
349
356
|
|
|
350
|
-
permissions = []
|
|
351
357
|
items = []
|
|
352
358
|
template_path = None
|
|
353
359
|
|
|
@@ -405,28 +411,32 @@ class HomePageItem(HomePageBase, PermissionsMixin):
|
|
|
405
411
|
|
|
406
412
|
class NavMenuTab(NavMenuBase, PermissionsMixin):
|
|
407
413
|
"""
|
|
408
|
-
|
|
409
|
-
|
|
414
|
+
This class represents a top-level Nautobot "menu context" such as Inventory or Networks.
|
|
415
|
+
|
|
416
|
+
It has a `name` (the menu context name) and a `weight` (which is mostly irrelevant these days).
|
|
417
|
+
|
|
418
|
+
It contains a list of `NavMenuGroup` instances as children.
|
|
410
419
|
|
|
411
|
-
|
|
420
|
+
In Nautobot 1.x, these could be augmented arbitrarily by apps and plugins;
|
|
421
|
+
but in 2.0 and later there is a fixed list of these (`nautobot.core.apps.MENU_TABS`) that cannot be altered.
|
|
412
422
|
"""
|
|
413
423
|
|
|
414
|
-
permissions = []
|
|
415
424
|
groups = []
|
|
416
425
|
|
|
417
426
|
@property
|
|
418
|
-
def initial_dict(self):
|
|
427
|
+
def initial_dict(self) -> dict:
|
|
428
|
+
"""Attributes to be stored when adding this item to the nav menu data for the first time."""
|
|
419
429
|
return {
|
|
420
|
-
"weight": self.weight,
|
|
421
430
|
"groups": {},
|
|
422
|
-
"permissions":
|
|
431
|
+
"permissions": self.permissions,
|
|
423
432
|
}
|
|
424
433
|
|
|
425
434
|
@property
|
|
426
|
-
def fixed_fields(self):
|
|
427
|
-
|
|
435
|
+
def fixed_fields(self) -> tuple:
|
|
436
|
+
"""Tuple of (name, attribute) entries describing fields that may not be altered after declaration."""
|
|
437
|
+
return (("weight", self.weight),)
|
|
428
438
|
|
|
429
|
-
def __init__(self, name, permissions=None, groups=None
|
|
439
|
+
def __init__(self, name, permissions=None, groups=None):
|
|
430
440
|
"""
|
|
431
441
|
Ensure tab properties.
|
|
432
442
|
|
|
@@ -434,203 +444,113 @@ class NavMenuTab(NavMenuBase, PermissionsMixin):
|
|
|
434
444
|
name (str): The name of the tab.
|
|
435
445
|
permissions (list): The permissions required to view this tab.
|
|
436
446
|
groups (list): List of groups to be rendered in this tab.
|
|
437
|
-
weight (int): The weight of this tab.
|
|
438
447
|
"""
|
|
439
448
|
super().__init__(permissions)
|
|
449
|
+
if name not in MENU_TABS:
|
|
450
|
+
raise ValueError(f"NavMenuTab name must be one of {MENU_TABS}")
|
|
440
451
|
self.name = name
|
|
441
|
-
self.weight = weight
|
|
442
452
|
if groups is not None:
|
|
443
453
|
if not isinstance(groups, (list, tuple)):
|
|
444
454
|
raise TypeError("Groups must be passed as a tuple or list.")
|
|
445
|
-
|
|
455
|
+
if not all(isinstance(group, NavMenuGroup) for group in groups):
|
|
446
456
|
raise TypeError("All groups defined in a tab must be an instance of NavMenuGroup")
|
|
447
457
|
self.groups = groups
|
|
448
458
|
|
|
449
459
|
|
|
450
460
|
class NavMenuGroup(NavMenuBase, PermissionsMixin):
|
|
451
461
|
"""
|
|
452
|
-
|
|
453
|
-
|
|
462
|
+
This class represents a group of menu items within a `NavMenuTab`.
|
|
463
|
+
|
|
464
|
+
It has a `name` (display string) and a `weight` which controls its position relative to other groups/items.
|
|
454
465
|
|
|
455
|
-
|
|
466
|
+
In Nautobot 1.x this could only contain `NavMenuItem`s as children;
|
|
467
|
+
in 2.x this has been relaxed to also permit a top-level `NavMenuGroup` to contain other `NavMenuGroup` objects.
|
|
456
468
|
"""
|
|
457
469
|
|
|
458
|
-
permissions = []
|
|
459
470
|
items = []
|
|
460
471
|
|
|
461
472
|
@property
|
|
462
|
-
def initial_dict(self):
|
|
473
|
+
def initial_dict(self) -> dict:
|
|
474
|
+
"""Attributes to be stored when adding this item to the nav menu data for the first time."""
|
|
463
475
|
return {
|
|
464
476
|
"weight": self.weight,
|
|
477
|
+
"permissions": self.permissions,
|
|
465
478
|
"items": {},
|
|
466
479
|
}
|
|
467
480
|
|
|
468
481
|
@property
|
|
469
|
-
def fixed_fields(self):
|
|
470
|
-
|
|
482
|
+
def fixed_fields(self) -> tuple:
|
|
483
|
+
"""Tuple of (name, attribute) entries describing fields that may not be altered after declaration."""
|
|
484
|
+
return (("weight", self.weight),)
|
|
471
485
|
|
|
472
|
-
def __init__(self, name,
|
|
486
|
+
def __init__(self, name, weight=1000, permissions=None, items=None):
|
|
473
487
|
"""
|
|
474
488
|
Ensure group properties.
|
|
475
489
|
|
|
476
490
|
Args:
|
|
477
491
|
name (str): The name of the group.
|
|
478
|
-
items (list): List of items to be rendered in this group.
|
|
479
492
|
weight (int): The weight of this group.
|
|
493
|
+
permissions (set): The permissions to access this group.
|
|
494
|
+
items (list): List of items to be rendered in this group.
|
|
480
495
|
"""
|
|
496
|
+
super().__init__(permissions)
|
|
481
497
|
self.name = name
|
|
482
498
|
self.weight = weight
|
|
483
499
|
|
|
484
500
|
if items is not None and not isinstance(items, (list, tuple)):
|
|
485
501
|
raise TypeError("Items must be passed as a tuple or list.")
|
|
486
|
-
|
|
487
|
-
raise TypeError("All items defined in a group must be an instance of NavMenuItem")
|
|
502
|
+
if not all(isinstance(item, (type(self), NavMenuItem)) for item in items):
|
|
503
|
+
raise TypeError("All items defined in a group must be an instance of NavMenuGroup or NavMenuItem")
|
|
488
504
|
self.items = items
|
|
489
505
|
|
|
490
506
|
|
|
491
507
|
class NavMenuItem(NavMenuBase, PermissionsMixin):
|
|
492
508
|
"""
|
|
493
|
-
This class represents a navigation menu item
|
|
494
|
-
|
|
509
|
+
This class represents a navigation menu item that leads to a specific page (a "leaf" in the nav menu, if you will).
|
|
510
|
+
|
|
511
|
+
These are contained within `NavMenuGroup` objects.
|
|
495
512
|
|
|
496
513
|
Links are specified as Django reverse URL strings.
|
|
497
|
-
Buttons are each specified as a list of NavMenuButton instances.
|
|
498
514
|
"""
|
|
499
515
|
|
|
500
516
|
@property
|
|
501
|
-
def initial_dict(self):
|
|
517
|
+
def initial_dict(self) -> dict:
|
|
518
|
+
"""Attributes to be stored when adding this item to the nav menu data for the first time."""
|
|
502
519
|
return {
|
|
503
|
-
"name": self.name,
|
|
504
520
|
"weight": self.weight,
|
|
505
|
-
"buttons": {},
|
|
506
521
|
"permissions": self.permissions,
|
|
507
|
-
"
|
|
508
|
-
"kwargs": {},
|
|
522
|
+
"link": self.link,
|
|
509
523
|
}
|
|
510
524
|
|
|
511
525
|
@property
|
|
512
|
-
def fixed_fields(self):
|
|
526
|
+
def fixed_fields(self) -> tuple:
|
|
527
|
+
"""Tuple of (name, attribute) entries describing fields that may not be altered after declaration."""
|
|
513
528
|
return (
|
|
514
|
-
("
|
|
529
|
+
("weight", self.weight),
|
|
515
530
|
("permissions", self.permissions),
|
|
531
|
+
("link", self.link),
|
|
516
532
|
)
|
|
517
533
|
|
|
518
|
-
permissions =
|
|
519
|
-
buttons = []
|
|
520
|
-
args = []
|
|
521
|
-
kwargs = {}
|
|
522
|
-
|
|
523
|
-
def __init__(self, link, name, args=None, kwargs=None, permissions=None, buttons=(), weight=1000):
|
|
534
|
+
def __init__(self, link, name, args=None, kwargs=None, permissions=None, weight=1000):
|
|
524
535
|
"""
|
|
525
536
|
Ensure item properties.
|
|
526
537
|
|
|
527
538
|
Args:
|
|
528
|
-
link (str): The link to be used for this item.
|
|
539
|
+
link (str): The named link to be used for this item. `reverse(link, args, kwargs)` will be called.
|
|
529
540
|
name (str): The name of the item.
|
|
530
541
|
args (list): Arguments that are being passed to the url with reverse() method
|
|
531
542
|
kwargs (dict): Keyword arguments are are being passed to the url with reverse() method
|
|
532
543
|
permissions (list): The permissions required to view this item.
|
|
533
|
-
buttons (list): List of buttons to be rendered in this item.
|
|
534
544
|
weight (int): The weight of this item.
|
|
535
545
|
"""
|
|
536
546
|
super().__init__(permissions)
|
|
537
|
-
self.link = link
|
|
538
547
|
self.name = name
|
|
539
548
|
self.weight = weight
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
elif not all(isinstance(button, NavMenuButton) for button in buttons):
|
|
546
|
-
raise TypeError("All buttons defined in an item must be an instance or subclass of NavMenuButton")
|
|
547
|
-
self.buttons = buttons
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
class NavMenuButton(NavMenuBase, PermissionsMixin):
|
|
551
|
-
"""
|
|
552
|
-
This class represents a button within a PluginMenuItem. Note that button colors should come from
|
|
553
|
-
ButtonColorChoices.
|
|
554
|
-
"""
|
|
555
|
-
|
|
556
|
-
@property
|
|
557
|
-
def initial_dict(self):
|
|
558
|
-
return {
|
|
559
|
-
"link": self.link,
|
|
560
|
-
"icon_class": self.icon_class,
|
|
561
|
-
"button_class": self.button_class,
|
|
562
|
-
"weight": self.weight,
|
|
563
|
-
"buttons": {},
|
|
564
|
-
"permissions": self.permissions,
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
@property
|
|
568
|
-
def fixed_fields(self):
|
|
569
|
-
return (
|
|
570
|
-
("button_class", self.button_class),
|
|
571
|
-
("icon_class", self.icon_class),
|
|
572
|
-
("link", self.link),
|
|
573
|
-
("permissions", self.permissions),
|
|
574
|
-
)
|
|
575
|
-
|
|
576
|
-
def __init__(
|
|
577
|
-
self,
|
|
578
|
-
link,
|
|
579
|
-
title,
|
|
580
|
-
icon_class,
|
|
581
|
-
button_class=ButtonActionColorChoices.DEFAULT,
|
|
582
|
-
permissions=None,
|
|
583
|
-
weight=1000,
|
|
584
|
-
):
|
|
585
|
-
"""
|
|
586
|
-
Ensure button properties.
|
|
587
|
-
|
|
588
|
-
Args:
|
|
589
|
-
link (str): The link to be used for this button.
|
|
590
|
-
title (str): The title of the button.
|
|
591
|
-
icon_class (str): The icon class to be used as the icon for the start of the button.
|
|
592
|
-
button_class (str): The button class defines to be used to define the style of the button.
|
|
593
|
-
permissions (list): The permissions required to view this button.
|
|
594
|
-
weight (int): The weight of this button.
|
|
595
|
-
"""
|
|
596
|
-
super().__init__(permissions)
|
|
597
|
-
self.link = link
|
|
598
|
-
self.title = title
|
|
599
|
-
self.icon_class = icon_class
|
|
600
|
-
self.weight = weight
|
|
601
|
-
self.button_class = button_class
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
class NavMenuAddButton(NavMenuButton):
|
|
605
|
-
"""Add button subclass."""
|
|
606
|
-
|
|
607
|
-
def __init__(self, *args, **kwargs):
|
|
608
|
-
"""Ensure button properties."""
|
|
609
|
-
if "title" not in kwargs:
|
|
610
|
-
kwargs["title"] = "Add"
|
|
611
|
-
if "icon_class" not in kwargs:
|
|
612
|
-
kwargs["icon_class"] = ButtonActionIconChoices.ADD
|
|
613
|
-
if "button_class" not in kwargs:
|
|
614
|
-
kwargs["button_class"] = ButtonActionColorChoices.ADD
|
|
615
|
-
if "weight" not in kwargs:
|
|
616
|
-
kwargs["weight"] = 100
|
|
617
|
-
super().__init__(*args, **kwargs)
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
class NavMenuImportButton(NavMenuButton):
|
|
621
|
-
"""Import button subclass."""
|
|
622
|
-
|
|
623
|
-
def __init__(self, *args, **kwargs):
|
|
624
|
-
"""Ensure button properties."""
|
|
625
|
-
if "title" not in kwargs:
|
|
626
|
-
kwargs["title"] = "Import"
|
|
627
|
-
if "icon_class" not in kwargs:
|
|
628
|
-
kwargs["icon_class"] = ButtonActionIconChoices.IMPORT
|
|
629
|
-
if "button_class" not in kwargs:
|
|
630
|
-
kwargs["button_class"] = ButtonActionColorChoices.IMPORT
|
|
631
|
-
if "weight" not in kwargs:
|
|
632
|
-
kwargs["weight"] = 200
|
|
633
|
-
super().__init__(*args, **kwargs)
|
|
549
|
+
try:
|
|
550
|
+
self.link = reverse(link, args=args, kwargs=kwargs)
|
|
551
|
+
except NoReverseMatch as e:
|
|
552
|
+
logger.error("Error in link construction for %s: %s", self.name, e)
|
|
553
|
+
self.link = ""
|
|
634
554
|
|
|
635
555
|
|
|
636
556
|
def post_migrate_send_nautobot_database_ready(sender, app_config, signal, **kwargs):
|
|
@@ -693,12 +613,10 @@ class CoreConfig(NautobotConfig):
|
|
|
693
613
|
|
|
694
614
|
super().ready()
|
|
695
615
|
|
|
696
|
-
#
|
|
697
|
-
from
|
|
698
|
-
from nautobot.extras.models import mixins
|
|
699
|
-
from taggit.managers import TaggableManager
|
|
616
|
+
# Register jobs last after everything else has been done.
|
|
617
|
+
from nautobot.core.celery import app, import_jobs_as_celery_tasks
|
|
700
618
|
|
|
701
|
-
|
|
619
|
+
import_jobs_as_celery_tasks(app, database_ready=False)
|
|
702
620
|
|
|
703
621
|
|
|
704
622
|
class NautobotConstanceConfig(ConstanceConfig):
|