Skip to content

Commit 777a300

Browse files
committed
Update participants/captain/reporter handling
1 parent e8d6abc commit 777a300

File tree

6 files changed

+41
-43
lines changed

6 files changed

+41
-43
lines changed

frontend/src/routes/$incidentId/components/ParticipantsList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function ParticipantsList({participants}: ParticipantsListProps) {
2222
<div className="text-content-headings flex-1 font-medium">
2323
{participant.name}
2424
</div>
25-
{participant.role && (
25+
{participant.role && participant.role !== 'Participant' && (
2626
<div className="text-content-secondary text-sm uppercase">
2727
{participant.role}
2828
</div>

frontend/src/routes/$incidentId/queries/incidentDetailQueryOptions.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {z} from 'zod';
55
const ParticipantSchema = z.object({
66
name: z.string(),
77
avatar_url: z.string().nullable(),
8-
role: z.string().nullable(),
8+
role: z.string(),
99
});
1010

1111
const ExternalLinksSchema = z.object({
@@ -14,6 +14,8 @@ const ExternalLinksSchema = z.object({
1414
datadog: z.string().nullable(),
1515
pagerduty: z.string().nullable(),
1616
statuspage: z.string().nullable(),
17+
notion: z.string().nullable(),
18+
linear: z.string().nullable(),
1719
});
1820

1921
const IncidentDetailSchema = z.object({

frontend/src/routes/components/Header.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ const mockIncidentDetail: IncidentDetail = {
6060
participants: [
6161
{
6262
name: 'John Doe',
63-
slack: '@johndoe',
6463
avatar_url: 'https://example.com/avatar.jpg',
65-
role: 'Incident Commander',
64+
role: 'Captain',
6665
},
6766
],
6867
external_links: {
@@ -71,6 +70,8 @@ const mockIncidentDetail: IncidentDetail = {
7170
datadog: null,
7271
pagerduty: null,
7372
statuspage: null,
73+
notion: null,
74+
linear: null,
7475
},
7576
};
7677

src/firetower/incidents/serializers.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from rest_framework import serializers
22

3-
from firetower.auth.serializers import UserSerializer
4-
53
from .models import Incident
64

75

@@ -70,10 +68,7 @@ class IncidentDetailUISerializer(serializers.ModelSerializer):
7068
id = serializers.CharField(source="incident_number", read_only=True)
7169

7270
# Full nested user data for captain/reporter
73-
captain = UserSerializer(read_only=True)
74-
reporter = UserSerializer(read_only=True)
75-
76-
# Participants with role information
71+
# Participants with role information (includes captain and reporter)
7772
participants = serializers.SerializerMethodField()
7873

7974
# Tags as arrays of strings (not full objects)
@@ -95,8 +90,6 @@ class Meta:
9590
"status",
9691
"severity",
9792
"is_private",
98-
"captain",
99-
"reporter",
10093
"participants",
10194
"affected_areas",
10295
"root_causes",
@@ -108,21 +101,23 @@ class Meta:
108101

109102
def get_participants(self, obj):
110103
"""
111-
Get all participants with their roles.
104+
Get all participants with their roles, with captain and reporter at the top.
112105
113-
Combines captain, reporter, and participants into one list
114-
matching frontend expectation.
106+
Order:
107+
1. Captain (if exists)
108+
2. Reporter (if exists)
109+
3. Other participants
115110
"""
116111
participants_list = []
117112
seen_users = set()
118113

119-
# Add captain
114+
# Add captain first
120115
if obj.captain and obj.captain.id not in seen_users:
121116
serializer = ParticipantSerializer(obj.captain, context={"incident": obj})
122117
participants_list.append(serializer.data)
123118
seen_users.add(obj.captain.id)
124119

125-
# Add reporter
120+
# Add reporter second
126121
if obj.reporter and obj.reporter.id not in seen_users:
127122
serializer = ParticipantSerializer(obj.reporter, context={"incident": obj})
128123
participants_list.append(serializer.data)

src/firetower/incidents/tests/test_serializers.py

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -119,34 +119,27 @@ def test_incident_detail_serialization(self):
119119
assert data["id"] == f"INC-{incident.id}"
120120
assert data["title"] == "Test Incident"
121121

122-
# Check nested users for captain/reporter (name and avatar only)
123-
assert data["captain"]["name"] == "Jane Captain"
124-
assert "avatar_url" in data["captain"]
125-
assert "email" not in data["captain"]
126-
127-
assert data["reporter"]["name"] == "John Reporter"
128-
assert "avatar_url" in data["reporter"]
129-
assert "email" not in data["reporter"]
122+
# Captain and reporter should NOT be separate fields
123+
assert "captain" not in data
124+
assert "reporter" not in data
130125

131-
# Check participants structure (matches frontend expectation)
132-
assert len(data["participants"]) == 3 # captain, reporter, participant
126+
# Check participants include captain, reporter, and other participants with roles
127+
assert len(data["participants"]) == 3
133128

134-
# Find each participant
135-
captain_participant = next(
136-
p for p in data["participants"] if p["role"] == "Captain"
137-
)
138-
assert captain_participant["name"] == "Jane Captain"
139-
assert "avatar_url" in captain_participant
129+
# First should be captain
130+
assert data["participants"][0]["name"] == "Jane Captain"
131+
assert data["participants"][0]["role"] == "Captain"
132+
assert "avatar_url" in data["participants"][0]
140133

141-
reporter_participant = next(
142-
p for p in data["participants"] if p["role"] == "Reporter"
143-
)
144-
assert reporter_participant["name"] == "John Reporter"
134+
# Second should be reporter
135+
assert data["participants"][1]["name"] == "John Reporter"
136+
assert data["participants"][1]["role"] == "Reporter"
137+
assert "avatar_url" in data["participants"][1]
145138

146-
other_participant = next(
147-
p for p in data["participants"] if p["role"] == "Participant"
148-
)
149-
assert other_participant["name"] == "Alice Participant"
139+
# Third should be participant
140+
assert data["participants"][2]["name"] == "Alice Participant"
141+
assert data["participants"][2]["role"] == "Participant"
142+
assert "avatar_url" in data["participants"][2]
150143

151144
# Check affected_areas and root_causes as arrays of strings
152145
assert "API" in data["affected_areas"]

src/firetower/incidents/tests/test_views.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,16 @@ def test_retrieve_incident(self):
175175
assert data["id"] == incident.incident_number
176176
assert data["title"] == "Test Incident"
177177

178+
# Captain and reporter should not be separate fields
179+
assert "captain" not in data
180+
assert "reporter" not in data
181+
182+
# Captain should be in participants list
183+
assert len(data["participants"]) == 1
184+
assert data["participants"][0]["name"] == "Jane Captain"
185+
assert data["participants"][0]["role"] == "Captain"
186+
178187
# Detail view includes full data
179-
assert "captain" in data
180-
assert data["captain"]["name"] == "Jane Captain"
181188
assert "affected_areas" in data
182189
assert "API" in data["affected_areas"]
183190
assert "external_links" in data

0 commit comments

Comments
 (0)