Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 56 additions & 14 deletions src/sentry/tasks/summaries/weekly_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,20 +459,20 @@ def record_delivery(self) -> bool:
return is_duplicate_detected


project_breakdown_colors = ["#422C6E", "#895289", "#D6567F", "#F38150", "#F2B713"]
project_breakdown_colors = ["#7553FF", "#7C2282", "#F0369A", "#FF9838", "#FFD00E"]
total_color = """
linear-gradient(
-45deg,
#ccc 25%,
#A29FAA 25%,
transparent 25%,
transparent 50%,
#ccc 50%,
#ccc 75%,
#A29FAA 50%,
#A29FAA 75%,
transparent 75%,
transparent
);
"""
other_color = "#f2f0fa"
other_color = "#DAD9DE"
group_status_to_color = {
GroupHistoryStatus.UNRESOLVED: "#FAD473",
GroupHistoryStatus.RESOLVED: "#8ACBBC",
Expand Down Expand Up @@ -513,19 +513,47 @@ def _pct_change(current: int, previous: int) -> str | None:

def get_group_status_badge(group: Group) -> tuple[str, str, str]:
"""
Returns a tuple of (text, background_color, border_color)
Should be similar to GroupStatusBadge.tsx in the frontend
Returns a tuple of (text, background_color, text_color)
Matches frontend Tag component: background.transparent.*.muted blended on white, content.* text.
"""
if group.status == GroupStatus.RESOLVED:
return ("Resolved", "rgba(108, 95, 199, 0.08)", "rgba(108, 95, 199, 0.5)")
return ("Resolved", "#E3F7E3", "#008900")
if group.status == GroupStatus.UNRESOLVED:
if group.substatus == GroupSubStatus.NEW:
return ("New", "rgba(245, 176, 0, 0.08)", "rgba(245, 176, 0, 0.55)")
return ("New", "#F9F0D2", "#A45200")
if group.substatus == GroupSubStatus.REGRESSED:
return ("Regressed", "rgba(108, 95, 199, 0.08)", "rgba(108, 95, 199, 0.5)")
return ("Regressed", "#EDEEFE", "#653DE9")
if group.substatus == GroupSubStatus.ESCALATING:
return ("Escalating", "rgba(245, 84, 89, 0.09)", "rgba(245, 84, 89, 0.5)")
return ("Ongoing", "rgba(219, 214, 225, 1)", "rgba(219, 214, 225, 1)")
return ("Escalating", "#FEE7E4", "#D50000")
return ("Ongoing", "#F0F0F2", "#6A6772")


def get_group_display(group: Group) -> dict[str, str]:
metadata = group.get_event_metadata()
event_type = group.get_event_type()
custom_title = metadata.get("title")

if event_type == "error":
title = (
custom_title
if custom_title and custom_title != "<unlabeled event>"
else metadata.get("type") or metadata.get("function") or "<unknown>"
)
message = metadata.get("value")
elif event_type in ("transaction", "generic"):
title = custom_title or group.title
message = metadata.get("value")
elif event_type == "csp":
title = custom_title or metadata.get("directive") or ""
message = metadata.get("message")
else:
title = custom_title or group.title
message = group.culprit

return {
"title": title,
"message": message or group.message or "",
}


def get_local_dates(ctx: OrganizationReportContext, user_id: int) -> tuple[datetime, datetime]:
Expand Down Expand Up @@ -681,20 +709,23 @@ def key_errors():
def all_key_errors():
for project_ctx in user_projects:
for group, count in project_ctx.key_errors_by_group:
display = get_group_display(group)
(
substatus,
substatus_color,
substatus_border_color,
substatus_text_color,
) = get_group_status_badge(group)

yield {
"count": count,
"group": group,
"title": display["title"],
"message": display["message"],
"status": "Unresolved",
"status_color": (group_status_to_color[GroupHistoryStatus.NEW]),
"group_substatus": substatus,
"group_substatus_color": substatus_color,
"group_substatus_border_color": substatus_border_color,
"group_substatus_text_color": substatus_text_color,
}

return heapq.nlargest(3, all_key_errors(), lambda d: d["count"])
Expand Down Expand Up @@ -723,9 +754,17 @@ def key_performance_issues():
def all_key_performance_issues():
for project_ctx in user_projects:
for group, group_history, count in project_ctx.key_performance_issues:
display = get_group_display(group)
(
substatus,
substatus_color,
substatus_text_color,
) = get_group_status_badge(group)
yield {
"count": count,
"group": group,
"title": display["title"],
"message": display["message"],
"status": (
group_history.get_status_display() if group_history else "Unresolved"
),
Expand All @@ -734,6 +773,9 @@ def all_key_performance_issues():
if group_history
else group_status_to_color[GroupHistoryStatus.NEW]
),
"group_substatus": substatus,
"group_substatus_color": substatus_color,
"group_substatus_text_color": substatus_text_color,
}

return heapq.nlargest(3, all_key_performance_issues(), lambda d: d["count"])
Expand Down
66 changes: 35 additions & 31 deletions src/sentry/templates/sentry/emails/reports/body.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
.project-breakdown .summary thead th {
font-size: 12px;
text-transform: uppercase;
color: #88859a;
color: #2f2936;
font-weight: 500;
}

Expand Down Expand Up @@ -198,8 +198,7 @@ <h4 class="total-count-title">Total Project Errors</h4>
<h1 style="margin: 0;" class="total-count">
{{ trends.total_error_count|small_count:1 }}
{% if show_week_over_week_metric and trends.error_pct_change %}
<span style="font-size: 14px; font-weight: 500; margin-left: 8px; padding: 2px 8px; border-radius: 12px; vertical-align: middle; background-color: #F2F0FA; color: #80708F;">{{ trends.error_pct_change }}</span>
<span style="font-size: 12px; font-weight: normal; color: #80708F; margin-left: 4px; vertical-align: middle;">(vs. last week)</span>
<span style="font-size: 14px; font-weight: 500; margin-left: 8px; padding: 2px 8px; border-radius: 12px; vertical-align: middle; background-color: #F2F0FA; color: #3A1873;">{{ trends.error_pct_change }}</span>
{% endif %}
</h1>
{% url 'sentry-organization-issue-list' organization.slug as issue_list %}
Expand All @@ -218,7 +217,7 @@ <h1 style="margin: 0;" class="total-count">
</tr>
{% empty %}
<tr>
<td height="1" style="background-color: #ebe9f7;"></td>
<td height="1" style="background-color: #DAD9DE;"></td>
</tr>
{% endfor %}
</table>
Expand All @@ -241,8 +240,7 @@ <h4 class="total-count-title">Total Project Transactions</h4>
<h1 style="margin: 0;" class="total-count">
{{ trends.total_transaction_count|small_count:1 }}
{% if show_week_over_week_metric and trends.transaction_pct_change %}
<span style="font-size: 14px; font-weight: 500; margin-left: 8px; padding: 2px 8px; border-radius: 12px; vertical-align: middle; background-color: #F2F0FA; color: #80708F;">{{ trends.transaction_pct_change }}</span>
<span style="font-size: 12px; font-weight: normal; color: #80708F; margin-left: 4px; vertical-align: middle;">(vs. last week)</span>
<span style="font-size: 14px; font-weight: 500; margin-left: 8px; padding: 2px 8px; border-radius: 12px; vertical-align: middle; background-color: #F2F0FA; color: #3A1873;">{{ trends.transaction_pct_change }}</span>
{% endif %}
</h1>
{% url 'sentry-organization-performance' organization.slug as performance_landing %}
Expand All @@ -260,7 +258,7 @@ <h1 style="margin: 0;" class="total-count">
</tr>
{% empty %}
<tr>
<td height="1" style="background-color: #ebe9f7;"></td>
<td height="1" style="background-color: #DAD9DE;"></td>
</tr>
{% endfor %}
</table>
Expand Down Expand Up @@ -329,22 +327,22 @@ <h1 style="font-weight: bold; font-size: 17px;">Something slow?</h1>
<h4>Errors by Issue Type</h4>
</td>
<td class="legend">
<span class="swatch" style="background-color: #DF5120;"></span>New<span class="quantity">: {% percent issue_summary.new_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
<span class="swatch" style="background-color: #FF7738;"></span>Reopened<span class="quantity">: {% percent issue_summary.reopened_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
<span class="swatch" style="background-color: #F9C7B9;"></span>Existing<span class="quantity">: {% percent issue_summary.existing_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
<span class="swatch" style="background-color: #FF002B;"></span>New<span class="quantity">: {% percent issue_summary.new_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
<span class="swatch" style="background-color: #FFCE00;"></span>Reopened<span class="quantity">: {% percent issue_summary.reopened_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
<span class="swatch" style="background-color: #DAD9DE;"></span>Existing<span class="quantity">: {% percent issue_summary.existing_issue_count issue_summary.all_issue_count "0.1f" %}%</span>
</td>
</tr>
<tr>
<td colspan="2">
<table>
<tr>
<td width="{% widthratio issue_summary.new_issue_count issue_summary.all_issue_count 100 %}%" title="New: {{ issue_summary.new_issue_count }} events" style="background-color: #DF5120">
<td width="{% widthratio issue_summary.new_issue_count issue_summary.all_issue_count 100 %}%" title="New: {{ issue_summary.new_issue_count }} events" style="background-color: #FF002B">
&nbsp;
</td>
<td width="{% widthratio issue_summary.reopened_issue_count issue_summary.all_issue_count 100 %}%" title="Reopened: {{ issue_summary.reopened_issue_count }} events" style="background-color: #FF7738">
<td width="{% widthratio issue_summary.reopened_issue_count issue_summary.all_issue_count 100 %}%" title="Reopened: {{ issue_summary.reopened_issue_count }} events" style="background-color: #FFCE00">
&nbsp;
</td>
<td width="{% widthratio issue_summary.existing_issue_count issue_summary.all_issue_count 100 %}%" title="Existing: {{ issue_summary.existing_issue_count }} events" style="background-color: #F9C7B9">
<td width="{% widthratio issue_summary.existing_issue_count issue_summary.all_issue_count 100 %}%" title="Existing: {{ issue_summary.existing_issue_count }} events" style="background-color: #DAD9DE">
&nbsp;
</td>
</tr>
Expand All @@ -361,26 +359,26 @@ <h4>Errors by Issue Type</h4>
<h4>Issues Breakdown</h4>
</td>
<td class="legend-inbox">
<span class="swatch" style="background-color: #F2B712;"></span>New<span class="quantity"> ({{ issue_summary.new_substatus_count }})</span>
<span class="swatch" style="background-color: #E9626E;"></span>Escalating<span class="quantity"> ({{ issue_summary.escalating_substatus_count }})</span>
<span class="swatch" style="background-color: #444674;"></span>Regressed<span class="quantity"> ({{ issue_summary.regression_substatus_count }})</span>
<span class="swatch" style="background-color: #DBD6E1;"></span>Ongoing<span class="quantity"> ({{ issue_summary.ongoing_substatus_count }})</span>
<span class="swatch" style="background-color: #EDCA60;"></span>New<span class="quantity"> ({{ issue_summary.new_substatus_count }})</span>
<span class="swatch" style="background-color: #FF978F;"></span>Escalating<span class="quantity"> ({{ issue_summary.escalating_substatus_count }})</span>
<span class="swatch" style="background-color: #B7B2FF;"></span>Regressed<span class="quantity"> ({{ issue_summary.regression_substatus_count }})</span>
<span class="swatch" style="background-color: #DAD9DE;"></span>Ongoing<span class="quantity"> ({{ issue_summary.ongoing_substatus_count }})</span>
</td>
</tr>
<tr>
<td colspan="2">
<table>
<tr>
<td width="{% widthratio issue_summary.new_substatus_count issue_summary.total_substatus_count 100 %}%" title="New: {{ issue_summary.new_substatus_count }} events" style="background-color: #F2B712">
<td width="{% widthratio issue_summary.new_substatus_count issue_summary.total_substatus_count 100 %}%" title="New: {{ issue_summary.new_substatus_count }} events" style="background-color: #EDCA60">
&nbsp;
</td>
<td width="{% widthratio issue_summary.escalating_substatus_count issue_summary.total_substatus_count 100 %}%" title="Escalating: {{ issue_summary.escalating_substatus_count }} events" style="background-color: #E9626E">
<td width="{% widthratio issue_summary.escalating_substatus_count issue_summary.total_substatus_count 100 %}%" title="Escalating: {{ issue_summary.escalating_substatus_count }} events" style="background-color: #FF978F">
&nbsp;
</td>
<td width="{% widthratio issue_summary.regression_substatus_count issue_summary.total_substatus_count 100 %}%" title="Regressed: {{ issue_summary.regression_substatus_count }} events" style="background-color: #444674">
<td width="{% widthratio issue_summary.regression_substatus_count issue_summary.total_substatus_count 100 %}%" title="Regressed: {{ issue_summary.regression_substatus_count }} events" style="background-color: #B7B2FF">
&nbsp;
</td>
<td width="{% widthratio issue_summary.ongoing_substatus_count issue_summary.total_substatus_count 100 %}%" title="Ongoing: {{ issue_summary.ongoing_substatus_count }} events" style="background-color: #DBD6E1">
<td width="{% widthratio issue_summary.ongoing_substatus_count issue_summary.total_substatus_count 100 %}%" title="Ongoing: {{ issue_summary.ongoing_substatus_count }} events" style="background-color: #DAD9DE">
&nbsp;
</td>
</tr>
Expand Down Expand Up @@ -408,17 +406,18 @@ <h4>Issues with the most errors</h4>
{% for a in key_errors %}
<div style="display: flex; flex-direction: row; margin-bottom: 8px; align-items: flex-start;">
<div style="width: 10%; font-size: 17px;">{{a.count|small_count:1}}</div>
<div style="width: 65%;">
<div style="width: 65%; min-width: 0;">
{% url 'sentry-organization-issue-detail' issue_id=a.group.id organization_slug=organization.slug as issue_detail %}
{% querystring referrer="weekly_report" notification_uuid=notification_uuid as query %}
<a style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; font-size: 17px; height: 24px;"
href="{% org_url organization issue_detail query=query %}">{{a.group.message}}</a>
<a title="{{a.title}}" style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width: auto; max-width: 100%; font-size: 17px; line-height: 1.2; margin-bottom: 2px;"
href="{% org_url organization issue_detail query=query %}">{{a.title}}</a>
<div title="{{a.message}}" style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width: auto; max-width: 100%; max-height: 38px; line-height: 1.2; font-size: 14px; color: #80708F; margin-bottom: 2px;">{{a.message}}</div>
<div style="font-size: 12px; color: #80708F;">{{a.group.project.name}}</div>
</div>
{% if a.group_substatus and a.group_substatus_color %}
<span style="background-color: {{a.group_substatus_color}}; border: 1px solid {{a.group_substatus_border_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; height: 100%;">{{a.group_substatus}}</span>
<span style="background-color: {{a.group_substatus_color}}; color: {{a.group_substatus_text_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; text-align: center;">{{a.group_substatus}}</span>
{% else %}
<span style="background-color: {{a.status_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; height: 100%;">{{a.status}}</span>
<span style="background-color: {{a.status_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; text-align: center;">{{a.status}}</span>
{% endif %}
</div>
{% endfor %}
Expand All @@ -430,14 +429,19 @@ <h4>Most frequent performance issues</h4>
{% for a in key_performance_issues %}
<div style="display: flex; flex-direction: row; margin-bottom: 8px; align-items: flex-start;">
<div style="width: 10%; font-size: 17px;">{{a.count|small_count:1}}</div>
<div style="width: 65%;">
<div style="width: 65%; min-width: 0;">
{% url 'sentry-organization-issue-detail' issue_id=a.group.id organization_slug=organization.slug as issue_detail %}
{% querystring referrer="weekly_report" notification_uuid=notification_uuid as query %}
<a style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; font-size: 17px; height: 24px;"
href="{% org_url organization issue_detail query=query %}">{{a.group.message}}</a>
<div style="font-size: 12px; color: #80708F;">{{a.group.get_type_display}}</div>
<a title="{{a.title}}" style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width: auto; max-width: 100%; font-size: 17px; line-height: 1.2; margin-bottom: 2px;"
href="{% org_url organization issue_detail query=query %}">{{a.title}}</a>
<div title="{{a.message}}" style="display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width: auto; max-width: 100%; max-height: 38px; line-height: 1.2; font-size: 14px; color: #80708F; margin-bottom: 2px;">{{a.message}}</div>
<div style="font-size: 12px; color: #80708F;">{{a.group.project.name}}</div>
</div>
<span style="background-color: {{a.status_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; height: 100%;">{{a.status}}</span>
{% if a.group_substatus and a.group_substatus_color %}
<span style="background-color: {{a.group_substatus_color}}; color: {{a.group_substatus_text_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; text-align: center;">{{a.group_substatus}}</span>
{% else %}
<span style="background-color: {{a.status_color}}; border-radius: 8px; font-size: 12px; align-self: center; padding: 2px 10px; margin-left: auto; text-align: center;">{{a.status}}</span>
{% endif %}
</div>
{% endfor %}
</div>
Expand Down
Loading
Loading