netbox-data-import 2.2.0__tar.gz → 2.3.0__tar.gz

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.
Files changed (222) hide show
  1. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/PKG-INFO +1 -1
  2. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/__init__.py +1 -1
  3. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/api/serializers.py +60 -12
  4. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/api/urls.py +4 -0
  5. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/api/views.py +107 -50
  6. netbox_data_import-2.3.0/netbox_data_import/graphql/schema.py +30 -0
  7. netbox_data_import-2.3.0/netbox_data_import/graphql/types.py +42 -0
  8. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/models.py +2 -0
  9. netbox_data_import-2.3.0/netbox_data_import/profile_yaml.py +350 -0
  10. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/helpers.py +17 -5
  11. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_atomic_exits.py +3 -0
  12. netbox_data_import-2.3.0/netbox_data_import/tests/test_configuration_surfaces.py +933 -0
  13. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_secret_containment.py +1 -1
  14. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_legacy_profile_yaml.py +1 -1
  15. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_standard_views.py +1 -1
  16. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_target_field_catalog.py +4 -4
  17. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_views.py +54 -55
  18. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_views_coverage2.py +1 -13
  19. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/views.py +5 -364
  20. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import.egg-info/PKG-INFO +1 -1
  21. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import.egg-info/SOURCES.txt +2 -0
  22. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/pyproject.toml +1 -1
  23. netbox_data_import-2.2.0/netbox_data_import/graphql/schema.py +0 -22
  24. netbox_data_import-2.2.0/netbox_data_import/graphql/types.py +0 -23
  25. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/LICENSE +0 -0
  26. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/README.md +0 -0
  27. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/adapter_config.py +0 -0
  28. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/adapter_forms.py +0 -0
  29. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/adapters.py +0 -0
  30. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/api/__init__.py +0 -0
  31. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/cable_target.py +0 -0
  32. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/catalog.py +0 -0
  33. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/contact_resolution.py +0 -0
  34. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/device_field_review.py +0 -0
  35. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/device_identity.py +0 -0
  36. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/field_keys.py +0 -0
  37. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/filters.py +0 -0
  38. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/flat_workbook.py +0 -0
  39. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/forms.py +0 -0
  40. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/graphql/__init__.py +0 -0
  41. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/graphql/filters.py +0 -0
  42. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/import_engine.py +0 -0
  43. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_adapter.py +0 -0
  44. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_backend.py +0 -0
  45. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_connection_test.py +0 -0
  46. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_credentials.py +0 -0
  47. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_settings.py +0 -0
  48. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_transport.py +0 -0
  49. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/inference_trust.py +0 -0
  50. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/ip_assignment.py +0 -0
  51. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/jobs.py +0 -0
  52. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0001_initial.py +0 -0
  53. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0002_importjob.py +0 -0
  54. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0003_remove_classrolemapping_unique_class_role_mapping_per_profile_and_more.py +0 -0
  55. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0004_features.py +0 -0
  56. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0005_deviceexistingmatch.py +0 -0
  57. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0006_deviceexistingmatch_asset_tag.py +0 -0
  58. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0007_manufacturermapping.py +0 -0
  59. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0008_unique_constraints.py +0 -0
  60. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0009_add_rack_type_to_classrolemapping.py +0 -0
  61. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0010_alter_manufacturermapping_id.py +0 -0
  62. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0011_importprofile_capture_extra_data.py +0 -0
  63. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0012_classrolemapping_rack_type_related_name.py +0 -0
  64. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0013_remove_columnmapping_unique_target.py +0 -0
  65. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0014_alter_columnmapping_target_field_and_more.py +0 -0
  66. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0015_cleanup_duplicate_device_matches.py +0 -0
  67. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0016_deviceexistingmatch_ndi_devicematch_profile_device.py +0 -0
  68. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0017_native_contact_sync.py +0 -0
  69. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0018_ignoredfielddifference.py +0 -0
  70. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0019_deviceimportsource.py +0 -0
  71. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0020_migrate_import_source_custom_field.py +0 -0
  72. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0021_importprofile_adapter_config.py +0 -0
  73. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0022_migrate_profile_adapter_config.py +0 -0
  74. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0023_drop_moved_profile_columns.py +0 -0
  75. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0024_rename_importjob_importexecution.py +0 -0
  76. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0025_remove_importexecution_dry_run_and_more.py +0 -0
  77. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0026_alter_sourcedocument_profile.py +0 -0
  78. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0027_cableclassmapping_terminationresolution.py +0 -0
  79. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0028_cableimportsource.py +0 -0
  80. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0029_alter_cableimportsource_from_text_and_more.py +0 -0
  81. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0030_remove_device_type_creation_config.py +0 -0
  82. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0031_inferencebackend.py +0 -0
  83. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0032_inference_timeout_floor.py +0 -0
  84. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/0033_resolutionproposal.py +0 -0
  85. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/migrations/__init__.py +0 -0
  86. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/navigation.py +0 -0
  87. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/netbox_reader.py +0 -0
  88. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/object_permissions.py +0 -0
  89. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/plan.py +0 -0
  90. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/preview_row_actions.py +0 -0
  91. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/proposal_decisions.py +0 -0
  92. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/proposal_jobs.py +0 -0
  93. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/proposal_presentation.py +0 -0
  94. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/proposal_response.py +0 -0
  95. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/proposal_tasks.py +0 -0
  96. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/resolution_proposals.py +0 -0
  97. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/review_workspace.py +0 -0
  98. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/signals.py +0 -0
  99. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/source_resolution.py +0 -0
  100. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/conflict_modal.js +0 -0
  101. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/contact_candidate_modal.js +0 -0
  102. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/preview_row_actions.js +0 -0
  103. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/preview_row_controls.js +0 -0
  104. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/split_name_modal.js +0 -0
  105. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/sync_row_modal.js +0 -0
  106. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/trace_proposals.js +0 -0
  107. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/static/netbox_data_import/js/trace_termination_picker.js +0 -0
  108. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tables.py +0 -0
  109. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/target_modules.py +0 -0
  110. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/target_runtime.py +0 -0
  111. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/template_content.py +0 -0
  112. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/_import_progress.html +0 -0
  113. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/_proposal_action.html +0 -0
  114. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/_proposal_card.html +0 -0
  115. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/analysis.html +0 -0
  116. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/bulk_yaml_import.html +0 -0
  117. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/cableclassmapping_edit.html +0 -0
  118. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/classrolemapping_edit.html +0 -0
  119. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/columnmapping_edit.html +0 -0
  120. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/columntransformrule_edit.html +0 -0
  121. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/device_import_data.html +0 -0
  122. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/devicetypemapping_edit.html +0 -0
  123. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/import_preview.html +0 -0
  124. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/import_profile_yaml.html +0 -0
  125. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/import_progress.html +0 -0
  126. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/import_results.html +0 -0
  127. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/import_setup.html +0 -0
  128. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/importexecution_list.html +0 -0
  129. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/importprofile.html +0 -0
  130. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/importprofile_list.html +0 -0
  131. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/inferencebackend.html +0 -0
  132. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/source_resolution_list.html +0 -0
  133. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/templates/netbox_data_import/trace_workspace.html +0 -0
  134. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/termination_proposal.py +0 -0
  135. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/__init__.py +0 -0
  136. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/conftest.py +0 -0
  137. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/fixtures/combined_name.xlsx +0 -0
  138. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/fixtures/sample_cans.xlsx +0 -0
  139. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/fixtures/trace_copper.xlsx +0 -0
  140. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/fixtures/trace_fiber.xlsx +0 -0
  141. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/inference_http.py +0 -0
  142. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/isolated_settings.py +0 -0
  143. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/mixins.py +0 -0
  144. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/mock_discipline.py +0 -0
  145. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/netbox_configuration.py +0 -0
  146. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/parallel.py +0 -0
  147. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_adapter_config.py +0 -0
  148. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_adapter_config_migration.py +0 -0
  149. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_api.py +0 -0
  150. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_cable_module.py +0 -0
  151. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_ci_configuration.py +0 -0
  152. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_comment_style.py +0 -0
  153. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_contact_resolution_ajax.py +0 -0
  154. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_contact_role_suggestion.py +0 -0
  155. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_contact_sync.py +0 -0
  156. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_cutover_edge_contracts.py +0 -0
  157. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_devcontainer_e2e.py +0 -0
  158. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_device_module.py +0 -0
  159. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_digest_indexed_models.py +0 -0
  160. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_execution_audit.py +0 -0
  161. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_graphql_filters.py +0 -0
  162. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_import_cutover.py +0 -0
  163. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_import_engine.py +0 -0
  164. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_import_execution.py +0 -0
  165. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_import_plan.py +0 -0
  166. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_import_source_migration.py +0 -0
  167. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_adapter.py +0 -0
  168. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_backend.py +0 -0
  169. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_connection_test.py +0 -0
  170. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_credentials.py +0 -0
  171. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_settings.py +0 -0
  172. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_inference_trust.py +0 -0
  173. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_installation_docs.py +0 -0
  174. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_ip_target.py +0 -0
  175. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_migrations.py +0 -0
  176. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_misc_coverage.py +0 -0
  177. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_mock_discipline.py +0 -0
  178. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_model_base_conventions.py +0 -0
  179. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_models.py +0 -0
  180. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_module_boundaries.py +0 -0
  181. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_navigation.py +0 -0
  182. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_netbox_reader.py +0 -0
  183. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_object_permission_writer.py +0 -0
  184. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_parallel_test_setup.py +0 -0
  185. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_placement_reference_locks.py +0 -0
  186. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_preview_assets.py +0 -0
  187. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_preview_state_ownership.py +0 -0
  188. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_pristine_preview_rows.py +0 -0
  189. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_profile_policy_crud_scoping.py +0 -0
  190. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_proposal_decisions.py +0 -0
  191. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_proposal_jobs.py +0 -0
  192. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_proposal_response.py +0 -0
  193. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_proposal_tasks.py +0 -0
  194. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_proposal_workspace.py +0 -0
  195. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_quick_action_input_bounds.py +0 -0
  196. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_quick_action_object_permissions.py +0 -0
  197. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_quick_action_profile_id.py +0 -0
  198. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_rack_module.py +0 -0
  199. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_release_metadata.py +0 -0
  200. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_remove_device_type_creation_config_migration.py +0 -0
  201. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_resolution_proposal_api.py +0 -0
  202. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_resolution_proposals.py +0 -0
  203. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_review_actions.py +0 -0
  204. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_review_resolutions.py +0 -0
  205. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_review_workspace.py +0 -0
  206. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_serial_display.py +0 -0
  207. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_source_adapter.py +0 -0
  208. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_target_module_edge_contracts.py +0 -0
  209. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_trace_decisions.py +0 -0
  210. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_trace_workbook.py +0 -0
  211. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_trace_workspace.py +0 -0
  212. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/tests/test_views_extra.py +0 -0
  213. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/trace_schema.py +0 -0
  214. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/trace_workbook.py +0 -0
  215. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/transform_regex.py +0 -0
  216. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/urls.py +0 -0
  217. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/utils.py +0 -0
  218. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import/values.py +0 -0
  219. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import.egg-info/dependency_links.txt +0 -0
  220. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import.egg-info/requires.txt +0 -0
  221. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/netbox_data_import.egg-info/top_level.txt +0 -0
  222. {netbox_data_import-2.2.0 → netbox_data_import-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netbox-data-import
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: NetBox plugin for importing data from external DCIM systems
5
5
  Author: Marcin Zieba
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ from typing import Any
4
4
 
5
5
  from netbox.plugins import PluginConfig
6
6
 
7
- __version__ = "2.2.0"
7
+ __version__ = "2.3.0"
8
8
 
9
9
 
10
10
  class NetBoxDataImportConfig(PluginConfig):
@@ -10,8 +10,11 @@ from rest_framework import serializers
10
10
 
11
11
  from ..adapters import DEFAULT_ADAPTER_KEY, get_adapter, selectable_adapter_choices
12
12
  from ..catalog import CATALOG
13
+ from ..forms import InferenceBackendForm
13
14
  from ..models import (
14
15
  ImportProfile,
16
+ CableClassMapping,
17
+ CableImportSource,
15
18
  ColumnMapping,
16
19
  ClassRoleMapping,
17
20
  DeviceTypeMapping,
@@ -63,6 +66,17 @@ class PolicySectionSerializer(PolicySectionApplicabilityMixin, ValidatedModelSer
63
66
  def validate_policy_row(self, attrs):
64
67
  """Check the fields this model resolves through the catalog. Subclasses override."""
65
68
 
69
+ def model_cleaned_values(self):
70
+ """Return request values after applying the model's canonical normalization."""
71
+ values = dict(self.validated_data)
72
+ if self.instance is None:
73
+ instance = self.Meta.model(**values)
74
+ instance.full_clean(validate_unique=False)
75
+ else:
76
+ # ValidatedModelSerializer.validate() applies request values and full_clean() to this instance.
77
+ instance = self.instance
78
+ return {name: getattr(instance, name) for name in values}
79
+
66
80
 
67
81
  def _validate_target_keys(instance, attrs, names, *, allow_candidates=True, required=False):
68
82
  """Reject a target key the profile's Source Adapter cannot supply."""
@@ -145,6 +159,24 @@ class ColumnMappingSerializer(PolicySectionSerializer):
145
159
  _validate_target_keys(self.instance, attrs, ("target_field",), required=True)
146
160
 
147
161
 
162
+ class CableClassMappingSerializer(PolicySectionSerializer):
163
+ """Serializer for CableClassMapping policy decisions."""
164
+
165
+ class Meta:
166
+ model = CableClassMapping
167
+ fields = [
168
+ "id",
169
+ "url",
170
+ "display",
171
+ "profile",
172
+ "cable_class",
173
+ "cable_type_resolved",
174
+ "cable_type",
175
+ "cable_profile_resolved",
176
+ "cable_profile",
177
+ ]
178
+
179
+
148
180
  class _RackTypeSlugField(serializers.SlugRelatedField):
149
181
  """SlugRelatedField for RackType that defers the queryset import."""
150
182
 
@@ -282,6 +314,30 @@ class ImportExecutionSerializer(serializers.ModelSerializer):
282
314
  read_only_fields = fields
283
315
 
284
316
 
317
+ class CableImportSourceSerializer(serializers.ModelSerializer):
318
+ """Read-only serializer for one Cable provenance record."""
319
+
320
+ class Meta:
321
+ model = CableImportSource
322
+ fields = [
323
+ "id",
324
+ "cable",
325
+ "profile",
326
+ "trace_identity",
327
+ "segment_index",
328
+ "from_text",
329
+ "to_text",
330
+ "direction",
331
+ "workbook_fingerprint",
332
+ "sheet",
333
+ "block_ordinal",
334
+ "row_start",
335
+ "row_end",
336
+ "export_timestamp",
337
+ ]
338
+ read_only_fields = fields
339
+
340
+
285
341
  class ResolutionProposalSerializer(serializers.ModelSerializer):
286
342
  """Read-only serializer for the Resolution Proposal audit record."""
287
343
 
@@ -328,28 +384,20 @@ class ResolutionProposalHistorySerializer(serializers.ModelSerializer):
328
384
 
329
385
 
330
386
  class InferenceBackendSerializer(NetBoxModelSerializer):
331
- """Serialize one Inference Backend row, without its credential reference.
387
+ """Serialize one Inference Backend row with a write-only credential reference.
332
388
 
333
389
  NetBox resolves this class by model name to freeze a delete event payload.
334
390
  """
335
391
 
392
+ credential_reference = serializers.JSONField(write_only=True)
393
+
336
394
  class Meta:
337
395
  model = InferenceBackend
338
396
  fields = [
339
397
  "id",
340
398
  "url",
341
399
  "display",
342
- "backend_key",
343
- "display_name",
344
- "adapter_type",
345
- "api_root",
346
- "model",
347
- "authentication",
348
- "response_mode",
349
- "connect_timeout",
350
- "read_timeout",
351
- "enabled",
352
- "tags",
400
+ *InferenceBackendForm.Meta.fields,
353
401
  "custom_fields",
354
402
  "created",
355
403
  "last_updated",
@@ -7,6 +7,8 @@ from netbox.api.routers import NetBoxRouter
7
7
 
8
8
  from .views import (
9
9
  ImportProfileViewSet,
10
+ CableClassMappingViewSet,
11
+ CableImportSourceViewSet,
10
12
  ColumnMappingViewSet,
11
13
  ClassRoleMappingViewSet,
12
14
  DeviceTypeMappingViewSet,
@@ -21,6 +23,8 @@ from .views import (
21
23
 
22
24
  router = NetBoxRouter()
23
25
  router.register("profiles", ImportProfileViewSet)
26
+ router.register("cable-class-mappings", CableClassMappingViewSet)
27
+ router.register("cable-provenance", CableImportSourceViewSet)
24
28
  router.register("column-mappings", ColumnMappingViewSet)
25
29
  router.register("class-role-mappings", ClassRoleMappingViewSet)
26
30
  router.register("device-type-mappings", DeviceTypeMappingViewSet)
@@ -3,16 +3,17 @@
3
3
  """DRF viewsets for the data-import plugin API."""
4
4
 
5
5
  from django.http import Http404
6
- from netbox.api.viewsets import NetBoxModelViewSet, NetBoxReadOnlyModelViewSet
6
+ from netbox.api.viewsets import NetBoxModelViewSet
7
7
  from rest_framework import mixins, permissions, viewsets
8
- from rest_framework.exceptions import ValidationError
8
+ from rest_framework.exceptions import PermissionDenied, ValidationError
9
9
  from rest_framework.permissions import DjangoModelPermissions
10
10
 
11
11
  from ..field_keys import SELECT_TERMINATION_TASK, parse_termination_field_key
12
12
  from ..models import (
13
13
  locked_profile_policy,
14
- locked_resolution_policy,
15
14
  ImportProfile,
15
+ CableClassMapping,
16
+ CableImportSource,
16
17
  ColumnMapping,
17
18
  ClassRoleMapping,
18
19
  DeviceTypeMapping,
@@ -23,8 +24,15 @@ from ..models import (
23
24
  InferenceBackend,
24
25
  ResolutionProposal,
25
26
  )
27
+ from ..object_permissions import (
28
+ ObjectPermissionDenied,
29
+ delete_permission_scoped_objects,
30
+ save_permission_scoped_object,
31
+ )
26
32
  from .serializers import (
27
33
  ImportProfileSerializer,
34
+ CableClassMappingSerializer,
35
+ CableImportSourceSerializer,
28
36
  ColumnMappingSerializer,
29
37
  ClassRoleMappingSerializer,
30
38
  DeviceTypeMappingSerializer,
@@ -84,6 +92,72 @@ class _PluginModelViewSet(_ProfileScopedQuerySetMixin, viewsets.ModelViewSet):
84
92
 
85
93
  permission_classes = [permissions.IsAuthenticated, DjangoModelPermissionsWithView]
86
94
 
95
+ def perform_create(self, serializer):
96
+ """Create one policy row inside its profile and object-permission scope."""
97
+ model = serializer.Meta.model
98
+ profile_id = serializer.validated_data["profile"].pk
99
+ try:
100
+ with locked_profile_policy(profile_id):
101
+ serializer.run_validation(serializer.initial_data)
102
+ values = serializer.model_cleaned_values()
103
+ profile = values.pop("profile")
104
+ result = save_permission_scoped_object(
105
+ self.request.user,
106
+ model,
107
+ {"pk": None, "profile": profile},
108
+ values,
109
+ on_existing="reject",
110
+ )
111
+ except ImportProfile.DoesNotExist:
112
+ raise Http404 from None
113
+ except ObjectPermissionDenied as exc:
114
+ raise PermissionDenied from exc
115
+ serializer.instance = result.instance
116
+
117
+ def perform_update(self, serializer):
118
+ """Update one policy row under every affected profile and object scope."""
119
+ model = serializer.Meta.model
120
+ row_pk = serializer.instance.pk
121
+ stored_profile_id = model.objects.filter(pk=row_pk).values_list("profile_id", flat=True).first()
122
+ if stored_profile_id is None:
123
+ raise Http404
124
+ requested_profile = serializer.validated_data.get("profile")
125
+ requested_profile_id = requested_profile.pk if requested_profile is not None else stored_profile_id
126
+ try:
127
+ with locked_profile_policy(stored_profile_id, requested_profile_id):
128
+ serializer.instance = model.objects.get(pk=row_pk, profile_id=stored_profile_id)
129
+ serializer.run_validation(serializer.initial_data)
130
+ result = save_permission_scoped_object(
131
+ self.request.user,
132
+ model,
133
+ {"pk": row_pk, "profile_id": stored_profile_id},
134
+ serializer.model_cleaned_values(),
135
+ )
136
+ except (model.DoesNotExist, ImportProfile.DoesNotExist):
137
+ raise Http404 from None
138
+ except ObjectPermissionDenied as exc:
139
+ raise PermissionDenied from exc
140
+ serializer.instance = result.instance
141
+
142
+ def perform_destroy(self, instance):
143
+ """Delete one policy row under its current profile and object scope."""
144
+ model = type(instance)
145
+ profile_id = model.objects.filter(pk=instance.pk).values_list("profile_id", flat=True).first()
146
+ if profile_id is None:
147
+ raise Http404
148
+ try:
149
+ with locked_profile_policy(profile_id):
150
+ deleted = delete_permission_scoped_objects(
151
+ self.request.user,
152
+ model.objects.filter(pk=instance.pk, profile_id=profile_id),
153
+ )
154
+ if deleted != 1:
155
+ raise Http404
156
+ except ImportProfile.DoesNotExist:
157
+ raise Http404 from None
158
+ except ObjectPermissionDenied as exc:
159
+ raise PermissionDenied from exc
160
+
87
161
 
88
162
  class ColumnMappingViewSet(_PluginModelViewSet):
89
163
  """CRUD viewset for ColumnMapping."""
@@ -92,6 +166,13 @@ class ColumnMappingViewSet(_PluginModelViewSet):
92
166
  serializer_class = ColumnMappingSerializer
93
167
 
94
168
 
169
+ class CableClassMappingViewSet(_PluginModelViewSet):
170
+ """CRUD viewset for CableClassMapping."""
171
+
172
+ queryset = CableClassMapping.objects.select_related("profile")
173
+ serializer_class = CableClassMappingSerializer
174
+
175
+
95
176
  class ClassRoleMappingViewSet(_PluginModelViewSet):
96
177
  """CRUD viewset for ClassRoleMapping."""
97
178
 
@@ -120,53 +201,12 @@ class ColumnTransformRuleViewSet(_PluginModelViewSet):
120
201
  serializer_class = ColumnTransformRuleSerializer
121
202
 
122
203
 
123
- def _revalidate_against_the_stored_row(serializer):
124
- """Read the resolution again and check the request against the row as it now stands.
125
-
126
- save() writes every field, so a request that changed another field first would otherwise be
127
- undone. The whole validation runs again rather than validate() alone, because the field checks
128
- read the stored row too, and the profile lock makes this reading of it authoritative. The
129
- result is discarded: the values are the request's own, which the first pass already holds.
130
- """
131
- serializer.instance = SourceResolution.objects.get(pk=serializer.instance.pk)
132
- serializer.run_validation(serializer.initial_data)
133
-
134
-
135
204
  class SourceResolutionViewSet(_PluginModelViewSet):
136
205
  """CRUD viewset for SourceResolution (rerere)."""
137
206
 
138
207
  queryset = SourceResolution.objects.select_related("profile")
139
208
  serializer_class = SourceResolutionSerializer
140
209
 
141
- # Each write serializes against an executing import, which holds the same profile row.
142
- def perform_create(self, serializer):
143
- """Create the resolution under the profile lock."""
144
- try:
145
- with locked_profile_policy(serializer.validated_data["profile"].pk):
146
- serializer.save()
147
- except ImportProfile.DoesNotExist:
148
- # The profile is read to validate the request, and can be deleted before the lock.
149
- raise Http404 from None
150
-
151
- def perform_update(self, serializer):
152
- """Update the resolution under its profile lock."""
153
- # ValidatedModelSerializer.validate() writes the request values onto the instance, so only
154
- # its primary key still names the stored row.
155
- try:
156
- with locked_resolution_policy(serializer.instance.pk):
157
- _revalidate_against_the_stored_row(serializer)
158
- serializer.save()
159
- except (SourceResolution.DoesNotExist, ImportProfile.DoesNotExist):
160
- raise Http404 from None
161
-
162
- def perform_destroy(self, instance):
163
- """Delete the resolution under its profile lock."""
164
- try:
165
- with locked_resolution_policy(instance.pk):
166
- instance.delete()
167
- except (SourceResolution.DoesNotExist, ImportProfile.DoesNotExist):
168
- raise Http404 from None
169
-
170
210
 
171
211
  class ImportExecutionViewSet(_ProfileScopedQuerySetMixin, viewsets.ReadOnlyModelViewSet):
172
212
  """Read-only viewset for the Import Execution audit history."""
@@ -176,6 +216,27 @@ class ImportExecutionViewSet(_ProfileScopedQuerySetMixin, viewsets.ReadOnlyModel
176
216
  permission_classes = [permissions.IsAuthenticated, DjangoModelPermissionsWithView]
177
217
 
178
218
 
219
+ class CableImportSourceViewSet(_ProfileScopedQuerySetMixin, viewsets.ReadOnlyModelViewSet):
220
+ """Read-only viewset for per-Cable import provenance."""
221
+
222
+ queryset = CableImportSource.objects.select_related("cable", "profile")
223
+ serializer_class = CableImportSourceSerializer
224
+ permission_classes = [permissions.IsAuthenticated, DjangoModelPermissionsWithView]
225
+
226
+ def get_queryset(self):
227
+ """Apply the profile scope and an optional Cable ID filter."""
228
+ profile_scope = ImportProfile.objects.restrict(self.request.user, "view")
229
+ qs = super().get_queryset().filter(profile__in=profile_scope)
230
+ cable_id = self.request.query_params.get("cable_id")
231
+ if cable_id is not None:
232
+ try:
233
+ cable_id = int(cable_id)
234
+ except (TypeError, ValueError) as exc:
235
+ raise ValidationError({"cable_id": "Enter a whole number."}) from exc
236
+ qs = qs.filter(cable_id=cable_id)
237
+ return qs
238
+
239
+
179
240
  class ResolutionProposalViewSet(_ProfileScopedQuerySetMixin, viewsets.ReadOnlyModelViewSet):
180
241
  """Read-only viewset for Resolution Proposal history."""
181
242
 
@@ -225,12 +286,8 @@ class ResolutionProposalHistoryViewSet(mixins.ListModelMixin, viewsets.GenericVi
225
286
  )
226
287
 
227
288
 
228
- class InferenceBackendViewSet(NetBoxReadOnlyModelViewSet):
229
- """Read-only viewset for Inference Backend rows.
230
-
231
- Read-only on purpose: a backend row carries the destination NetBox itself calls, and the UI form
232
- is the one place that validates the `api_root` trust boundary against the allowlist.
233
- """
289
+ class InferenceBackendViewSet(NetBoxModelViewSet):
290
+ """CRUD viewset whose configuration fields derive from the Inference Backend form."""
234
291
 
235
292
  queryset = InferenceBackend.objects.prefetch_related("tags")
236
293
  serializer_class = InferenceBackendSerializer
@@ -0,0 +1,30 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (C) 2025 Marcin Zieba <marcinpsk@gmail.com>
3
+
4
+ """GraphQL queries registered with NetBox."""
5
+
6
+ import strawberry
7
+ import strawberry_django
8
+
9
+ from .types import CableClassMappingType, ImportProfileType
10
+
11
+
12
+ @strawberry.type(name="Query")
13
+ class ImportProfilesQuery:
14
+ """Expose import profile detail and list queries."""
15
+
16
+ import_profile: ImportProfileType = strawberry_django.field()
17
+ import_profile_list: list[ImportProfileType] = strawberry_django.field()
18
+
19
+
20
+ @strawberry.type(name="Query")
21
+ class CableClassMappingsQuery:
22
+ """Expose CableClass mapping detail and list queries."""
23
+
24
+ cable_class_mapping: CableClassMappingType = strawberry_django.field()
25
+ cable_class_mapping_list: list[CableClassMappingType] = strawberry_django.field()
26
+
27
+
28
+ schema = [ImportProfilesQuery, CableClassMappingsQuery]
29
+
30
+ __all__ = ("CableClassMappingsQuery", "ImportProfilesQuery", "schema")
@@ -0,0 +1,42 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (C) 2025 Marcin Zieba <marcinpsk@gmail.com>
3
+
4
+ """GraphQL object types for import profile configuration."""
5
+
6
+ import strawberry_django
7
+ from netbox.graphql.types import BaseObjectType, NetBoxObjectType
8
+
9
+ from netbox_data_import.models import CableClassMapping, ImportProfile
10
+
11
+ from .filters import ImportProfileFilter
12
+
13
+ _type_kwargs = {"fields": "__all__", "pagination": True}
14
+ if ImportProfileFilter is not None: # pragma: no cover
15
+ _type_kwargs["filters"] = ImportProfileFilter
16
+
17
+
18
+ @strawberry_django.type(ImportProfile, **_type_kwargs)
19
+ class ImportProfileType(NetBoxObjectType):
20
+ """One saved source-file import configuration."""
21
+
22
+
23
+ @strawberry_django.type(
24
+ CableClassMapping,
25
+ fields=[
26
+ "id",
27
+ "profile",
28
+ "cable_class",
29
+ "cable_type_resolved",
30
+ "cable_type",
31
+ "cable_profile_resolved",
32
+ "cable_profile",
33
+ ],
34
+ pagination=True,
35
+ )
36
+ class CableClassMappingType(BaseObjectType):
37
+ """One trace CableClass policy decision."""
38
+
39
+ profile: ImportProfileType
40
+
41
+
42
+ __all__ = ("CableClassMappingType", "ImportProfileType")
@@ -1784,6 +1784,8 @@ class CableImportSource(DigestIndexedMixin):
1784
1784
  DIGEST_SOURCE_FIELD = "trace_identity"
1785
1785
  DIGEST_FIELD = "trace_key"
1786
1786
 
1787
+ objects = RestrictedQuerySet.as_manager()
1788
+
1787
1789
  cable = models.ForeignKey(
1788
1790
  to="dcim.Cable",
1789
1791
  on_delete=models.CASCADE,