diff --git a/events/utils.py b/events/utils.py
index d8ea8a6..12b2f5c 100644
--- a/events/utils.py
+++ b/events/utils.py
@@ -1,3 +1,4 @@
+from os.path import basename
from datetime import datetime, timezone
from uuid import UUID
import json
@@ -165,3 +166,28 @@ def apply_sourcemaps(event_data):
frame['filename'] = token.src
frame['function'] = token.name
# frame["colno"] = token.src_col + TO_DISPLAY not actually used
+
+
+def get_sourcemap_images(event_data):
+ # NOTE: butchered copy/paste of apply_sourcemaps; refactoring for DRY is a TODO
+ images = event_data.get("debug_meta", {}).get("images", [])
+ if not images:
+ return []
+
+ debug_id_for_filename = {
+ image["code_file"]: UUID(image["debug_id"])
+ for image in images
+ if "debug_id" in image and "code_file" in image and image["type"] == "sourcemap"
+ }
+
+ metadata_obj_lookup = {
+ metadata_obj.debug_id: metadata_obj
+ for metadata_obj in FileMetadata.objects.filter(
+ debug_id__in=debug_id_for_filename.values(), file_type="source_map").select_related("file")
+ }
+
+ return [
+ (basename(filename),
+ f"{debug_id} " + (" (uploaded)" if debug_id in metadata_obj_lookup else " (not uploaded)"))
+ for filename, debug_id in debug_id_for_filename.items()
+ ]
diff --git a/issues/templates/issues/event_details.html b/issues/templates/issues/event_details.html
index 42efa54..249f9bb 100644
--- a/issues/templates/issues/event_details.html
+++ b/issues/templates/issues/event_details.html
@@ -203,6 +203,19 @@ the fact that we commented-out rather than clobbered reveals a small amount of d
{% endif %}
+{% if sourcemaps_images %}
+
Sourcemap IDs
+
+
+ {% for key, value in sourcemaps_images %}
+
+
{{ key }}
+
{{ value|linebreaks }}
+
+ {% endfor %}
+
+{% endif %}
+
{% if parsed_data.extra %}
diff --git a/issues/views.py b/issues/views.py
index d547a17..5d19031 100644
--- a/issues/views.py
+++ b/issues/views.py
@@ -35,7 +35,7 @@ from tags.search import search_issues, search_events, search_events_optimized
from .models import Issue, IssueQuerysetStateManager, IssueStateManager, TurningPoint, TurningPointKind
from .forms import CommentForm
from .utils import get_values, get_main_exception
-from events.utils import annotate_with_meta, apply_sourcemaps
+from events.utils import annotate_with_meta, apply_sourcemaps, get_sourcemap_images
logger = logging.getLogger("bugsink.issues")
@@ -658,6 +658,15 @@ def issue_event_details(request, issue, event_pk=None, digest_order=None, nav=No
contexts = get_contexts_enriched_with_ua(parsed_data)
+ try:
+ sourcemaps_images = get_sourcemap_images(parsed_data)
+ except Exception as e:
+ if settings.DEBUG or settings.I_AM_RUNNING == "TEST":
+ # when developing/testing, I _do_ want to get notified
+ raise
+ # sourcemaps are still experimental; we don't want to fail on them, so we just log the error and move on.
+ capture_or_log_exception(e, logger)
+
return render(request, "issues/event_details.html", {
"tab": "event-details",
"this_view": "event_details",
@@ -671,6 +680,7 @@ def issue_event_details(request, issue, event_pk=None, digest_order=None, nav=No
"logentry_info": logentry_info,
"deployment_info": deployment_info,
"contexts": contexts,
+ "sourcemaps_images": sourcemaps_images,
"mute_options": GLOBAL_MUTE_OPTIONS,
"q": request.GET.get("q", ""),
# event_qs_count is not used when there is no q, so no need to calculate it in that case