Skip to content

Commit ab143fe

Browse files
committed
feat: add incident_id field to ticket model and related components
- Added incident_id to the ticket mapping in app.py. - Updated csv_data.py to include incident_id when converting CSV rows to tickets. - Modified operations.py to define incident_id as a CSV ticket field. - Enhanced the Ticket model in tickets.py to include incident_id. - Updated usecase_demo.py to accommodate changes in ticket structure. - Modified CSVTicketTable.jsx to display incident_id in the ticket table. - Updated TicketList.jsx to filter and display incident_id in the ticket list. - Enhanced TicketsWithoutAnAssignee.jsx to include incident_id in ticket operations. - Updated UsecaseDemoPage.jsx to pass matchingTickets to the render function. - Enhanced demoDefinitions.js to improve prompts for use case demos. - Added SLA Breach Overview result view in resultViews.jsx to visualize SLA status of tickets. Signed-off-by: Andre Bossard <anbossar@microsoft.com>
1 parent 7c48b68 commit ab143fe

12 files changed

Lines changed: 655 additions & 182 deletions

File tree

backend/agents.py

Lines changed: 260 additions & 82 deletions
Large diffs are not rendered by default.

backend/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ def _map_mcp_ticket_to_frontend(mcp_ticket: dict) -> dict:
375375

376376
return {
377377
"id": str(mcp_ticket.get("id", "")),
378+
"incident_id": mcp_ticket.get("incident_id"),
378379
"title": mcp_ticket.get("summary", ""),
379380
"description": mcp_ticket.get("description", ""),
380381
"status": status,

backend/csv_data.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ def csv_row_to_ticket(row: CSVTicketRow) -> Ticket:
290290

291291
return Ticket(
292292
id=ticket_id,
293+
incident_id=row.incident_id or row.entry_id or None,
293294
summary=row.summary or "No summary",
294295
description=row.notes or row.summary or "No description",
295296
status=map_status(row.status or row.status_ppl),

backend/operations.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222

2323
CSV_TICKET_FIELDS = [
24+
{"name": "incident_id", "label": "Incident ID", "type": "string"},
2425
{"name": "id", "label": "ID", "type": "uuid"},
2526
{"name": "summary", "label": "Summary", "type": "string"},
2627
{"name": "status", "label": "Status", "type": "enum"},

backend/tickets.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class Ticket(BaseModel):
159159
"""
160160
# Core identifiers
161161
id: UUID = Field(..., description="Unique ticket identifier")
162+
incident_id: Optional[str] = Field(None, description="Original incident ID (INC...)")
162163

163164
# Summary and description
164165
summary: str = Field(..., max_length=500, description="Short issue summary")

backend/usecase_demo.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,13 @@ async def _execute_run(self, run_id: str) -> None:
191191
# Enforce a predictable output block for table rendering.
192192
structured_prompt = (
193193
f"{run.prompt}\n\n"
194-
"Zusatzformat:\n"
195-
"- Gib zuerst eine kurze Zusammenfassung.\n"
196-
"- Füge danach einen JSON-Codeblock mit `rows` hinzu.\n"
197-
"- JSON-Schema:\n"
198-
" {\"rows\": [{\"menu_point\": \"...\", \"project_name\": \"...\", "
199-
"\"summary\": \"...\", \"agent_prompt\": \"...\", \"ticket_ids\": \"...\", "
200-
"\"csv_evidence\": \"...\"}]}\n"
201-
"- Falls keine sinnvollen Zeilen existieren, gib `{\"rows\": []}` zurück."
194+
"Antwortformat:\n"
195+
"- Führe die Anfrage mit möglichst wenigen Tool-Aufrufen aus.\n"
196+
"- Nutze kompakte fields und sinnvolle limits.\n"
197+
"- Fordere notes/resolution nur bei explizitem Bedarf an.\n"
198+
"- Gib einen JSON-Codeblock mit {\"rows\": [...]} zurück.\n"
199+
"- Falls keine sinnvollen Zeilen existieren, gib {\"rows\": []} zurück.\n"
200+
"- Optional danach: kurze Zusammenfassung in 2-4 Stichpunkten."
202201
)
203202

204203
try:

frontend/src/features/csvtickets/CSVTicketTable.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export default function CSVTicketTable() {
219219

220220
// Selected columns
221221
const [selectedFields, setSelectedFields] = useState([
222-
'summary', 'status', 'priority', 'assignee', 'assigned_group',
222+
'incident_id', 'summary', 'status', 'priority', 'assignee', 'assigned_group',
223223
'requester_name', 'city', 'created_at'
224224
])
225225

@@ -313,6 +313,12 @@ export default function CSVTicketTable() {
313313
const renderCell = (ticket, fieldName) => {
314314
const value = ticket[fieldName]
315315

316+
if (fieldName === 'incident_id') {
317+
return value ? (
318+
<span style={{ fontFamily: 'monospace', fontWeight: 600, letterSpacing: '0.02em' }}>{value}</span>
319+
) : '—'
320+
}
321+
316322
if (fieldName === 'status') {
317323
return getStatusBadge(value)
318324
}

frontend/src/features/tickets/TicketList.jsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ function filterTickets(tickets, searchTerm, priorityFilter, statusFilter) {
291291
const term = searchTerm.toLowerCase()
292292
filtered = filtered.filter(
293293
(ticket) =>
294+
ticket.incident_id?.toLowerCase().includes(term) ||
294295
ticket.id?.toLowerCase().includes(term) ||
295296
ticket.summary?.toLowerCase().includes(term) ||
296297
ticket.requester_name?.toLowerCase().includes(term) ||
@@ -333,6 +334,18 @@ export default function TicketList() {
333334

334335
// Columns for DataGrid
335336
const columns = [
337+
createTableColumn({
338+
columnId: 'incident_id',
339+
compare: (a, b) => (a.incident_id || '').localeCompare(b.incident_id || ''),
340+
renderHeaderCell: () => 'Incident ID',
341+
renderCell: (item) => (
342+
<TableCellLayout>
343+
<Text style={{ fontFamily: 'monospace', fontSize: tokens.fontSizeBase200, fontWeight: tokens.fontWeightSemibold }}>
344+
{item.incident_id || '—'}
345+
</Text>
346+
</TableCellLayout>
347+
),
348+
}),
336349
createTableColumn({
337350
columnId: 'summary',
338351
compare: (a, b) => (a.summary || '').localeCompare(b.summary || ''),
@@ -595,6 +608,11 @@ export default function TicketList() {
595608
{/* Detail Header */}
596609
<div className={styles.detailHeader}>
597610
<Text className={styles.detailTitle}>{detail.summary}</Text>
611+
{detail.incident_id && (
612+
<Text style={{ fontFamily: 'monospace', fontSize: tokens.fontSizeBase200, color: tokens.colorNeutralForeground3, marginBottom: tokens.spacingVerticalXS, display: 'block' }}>
613+
{detail.incident_id}
614+
</Text>
615+
)}
598616
<div className={styles.detailMeta}>
599617
<Badge appearance={getStatusAppearance(detail.status)} className={styles.statusBadge}>
600618
{detail.status?.replace('_', ' ')}

frontend/src/features/tickets/TicketsWithoutAnAssignee.jsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function filterTickets(tickets, searchTerm, priorityFilter) {
157157
const term = searchTerm.toLowerCase()
158158
filtered = filtered.filter(
159159
(ticket) =>
160-
ticket.id.toLowerCase().includes(term) ||
160+
(ticket.incident_id || ticket.id).toLowerCase().includes(term) ||
161161
ticket.title.toLowerCase().includes(term) ||
162162
ticket.description.toLowerCase().includes(term)
163163
)
@@ -194,12 +194,14 @@ export default function TicketsWithoutAnAssignee() {
194194
// Columns for DataGrid
195195
const columns = [
196196
createTableColumn({
197-
columnId: 'id',
198-
compare: (a, b) => a.id.localeCompare(b.id),
199-
renderHeaderCell: () => 'ID',
197+
columnId: 'incident_id',
198+
compare: (a, b) => (a.incident_id || a.id).localeCompare(b.incident_id || b.id),
199+
renderHeaderCell: () => 'Incident ID',
200200
renderCell: (item) => (
201201
<TableCellLayout>
202-
<Text weight="semibold">{item.id}</Text>
202+
<Text weight="semibold" style={{ fontFamily: 'monospace' }}>
203+
{item.incident_id || item.id}
204+
</Text>
203205
</TableCellLayout>
204206
),
205207
}),
@@ -246,7 +248,7 @@ export default function TicketsWithoutAnAssignee() {
246248

247249
const handleReminder = () => {
248250
if (selectedTicket) {
249-
setReminderMessage(`Erinnerung für Ticket ${selectedTicket.id} wurde gesendet.`)
251+
setReminderMessage(`Erinnerung für Ticket ${selectedTicket.incident_id || selectedTicket.id} wurde gesendet.`)
250252
// TODO: Backend integration - send reminder API call
251253
}
252254
}
@@ -268,15 +270,15 @@ export default function TicketsWithoutAnAssignee() {
268270
const handleMarkAsGood = () => {
269271
if (selectedTicket) {
270272
setTicketDecisions(prev => ({ ...prev, [selectedTicket.id]: 'GOOD' }))
271-
setReminderMessage(`Ticket ${selectedTicket.id} als GOOD markiert.`)
273+
setReminderMessage(`Ticket ${selectedTicket.incident_id || selectedTicket.id} als GOOD markiert.`)
272274
// TODO: Backend integration - update ticket status
273275
}
274276
}
275277

276278
const handleMarkAsEscalate = () => {
277279
if (selectedTicket) {
278280
setTicketDecisions(prev => ({ ...prev, [selectedTicket.id]: 'ESCALATE' }))
279-
setReminderMessage(`Ticket ${selectedTicket.id} zur Eskalation markiert.`)
281+
setReminderMessage(`Ticket ${selectedTicket.incident_id || selectedTicket.id} zur Eskalation markiert.`)
280282
// TODO: Backend integration - escalate ticket
281283
}
282284
}
@@ -387,8 +389,10 @@ export default function TicketsWithoutAnAssignee() {
387389
</div>
388390

389391
<div className={styles.detailField}>
390-
<Text className={styles.detailLabel}>Ticket ID</Text>
391-
<Text className={styles.detailValue}>{selectedTicket.id}</Text>
392+
<Text className={styles.detailLabel}>Incident ID</Text>
393+
<Text className={styles.detailValue} style={{ fontFamily: 'monospace', fontWeight: 600 }}>
394+
{selectedTicket.incident_id || selectedTicket.id}
395+
</Text>
392396
</div>
393397

394398
<div className={styles.detailField}>

frontend/src/features/usecase-demo/UsecaseDemoPage.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ export default function UsecaseDemoPage({ definition }) {
427427
{config.description && (
428428
<Text size={200} className={styles.viewDescription}>{config.description}</Text>
429429
)}
430-
{config.render({ run: currentRun, markdown: visibleResultMarkdown, styles })}
430+
{config.render({ run: currentRun, markdown: visibleResultMarkdown, styles, matchingTickets, isLoadingTickets })}
431431
</div>
432432
))
433433
)}

0 commit comments

Comments
 (0)