Backend (incident_correlator.py):

- Create path (line ~1274): title only uses "at {location}" when location_coords is also set
- Update path (line ~1226): same guard — best_coords must be truthy alongside best_location

Frontend (MapView.tsx):
- Desktop sidebar: cards with location_coords → <button> fly-to; cards without → <a href> that navigates to the incident page with "View details →" text
- Mobile drawer: same split — with coords fly-to+close, without coords navigate via <a>
- Removed the "no coords" italic placeholder text; the card behavior itself makes it clear
This commit is contained in:
Logan
2026-06-07 03:34:15 -04:00
parent e55412d8c7
commit 4e0e0fc79f
2 changed files with 79 additions and 54 deletions
@@ -1223,7 +1223,7 @@ async def _update_incident(
talkgroup_name
or (f"TGID {talkgroup_id}" if talkgroup_id else inc.get("title", "").split("")[-1])
)
if primary_tag and best_location and primary_tag.lower() != best_location.lower():
if primary_tag and best_location and best_coords and primary_tag.lower() != best_location.lower():
updates["title"] = f"{primary_tag} at {best_location}"
elif primary_tag and tg_label:
updates["title"] = f"{primary_tag}{tg_label}"
@@ -1271,7 +1271,7 @@ async def _create_incident(
# Build a descriptive title from tags + location when available
content_tags = [t for t in tags if t != "auto-generated"]
primary_tag = _tag_to_title(content_tags[0]) if content_tags else None
if primary_tag and location and primary_tag.lower() != location.lower():
if primary_tag and location and location_coords and primary_tag.lower() != location.lower():
title = f"{primary_tag} at {location}"
elif primary_tag:
title = f"{primary_tag}{tg_label}"
+77 -52
View File
@@ -518,51 +518,59 @@ export default function MapView({ nodes, activeCalls, incidents = [], lastUpdate
const color = INCIDENT_COLORS[inc.type ?? "other"] ?? INCIDENT_COLORS.other;
const age = inc.started_at ? timeAgo(new Date(inc.started_at)) : null;
const unitCount = inc.units?.length ?? 0;
const baseClass = "w-full text-left bg-gray-950/85 backdrop-blur-sm border rounded-lg px-3 py-2 text-xs font-mono hover:brightness-110 transition-all";
const cardBody = (
<>
<div className="flex items-center gap-1.5 mb-0.5">
<span
className="inline-block w-2 h-2 rounded-sm flex-shrink-0"
style={{ background: color }}
/>
<span
className="uppercase tracking-wide font-semibold text-[10px]"
style={{ color }}
>
{inc.type ?? "other"}
</span>
</div>
<p className="text-white font-semibold leading-snug truncate">
{inc.title ?? "Incident"}
</p>
{inc.location && (
<p className="text-gray-500 truncate mt-0.5">{inc.location}</p>
)}
<div className="flex items-center justify-between mt-0.5">
{age && <span className="text-gray-600">{age}</span>}
{unitCount > 0 && (
<span className="text-gray-600">{unitCount} unit{unitCount !== 1 ? "s" : ""}</span>
)}
</div>
{!inc.location_coords && (
<p className="text-[10px] text-blue-700 mt-1">View details </p>
)}
</>
);
if (inc.location_coords) {
return (
<button
key={inc.incident_id}
onClick={() => handleIncidentSelect(inc)}
className={baseClass}
style={{ borderColor: color + "55" }}
>
{cardBody}
</button>
);
}
return (
<div
<a
key={inc.incident_id}
className="w-full text-left bg-gray-950/85 backdrop-blur-sm border rounded-lg px-3 py-2 text-xs font-mono hover:brightness-110 transition-all"
href={`/incidents/${inc.incident_id}`}
className={`block ${baseClass}`}
style={{ borderColor: color + "55" }}
>
<button
onClick={() => handleIncidentSelect(inc)}
className="w-full text-left"
>
<div className="flex items-center gap-1.5 mb-0.5">
<span
className="inline-block w-2 h-2 rounded-sm flex-shrink-0"
style={{ background: color }}
/>
<span
className="uppercase tracking-wide font-semibold text-[10px]"
style={{ color }}
>
{inc.type ?? "other"}
</span>
</div>
<p className="text-white font-semibold leading-snug truncate">
{inc.title ?? "Incident"}
</p>
{inc.location && (
<p className="text-gray-500 truncate mt-0.5">{inc.location}</p>
)}
<div className="flex items-center justify-between mt-0.5">
{age && <span className="text-gray-600">{age}</span>}
{unitCount > 0 && (
<span className="text-gray-600">{unitCount} unit{unitCount !== 1 ? "s" : ""}</span>
)}
</div>
{!inc.location_coords && (
<p className="text-gray-700 italic mt-0.5">no coords</p>
)}
</button>
<a
href={`/incidents/${inc.incident_id}`}
className="block text-[10px] text-blue-700 hover:text-blue-500 mt-1 transition-colors"
>
View details
</a>
</div>
{cardBody}
</a>
);
})}
</div>
@@ -580,22 +588,39 @@ export default function MapView({ nodes, activeCalls, incidents = [], lastUpdate
<div className="bg-gray-950/95 border-t border-gray-800 max-h-52 overflow-y-auto px-3 py-2 space-y-1.5">
{incidents.map((inc) => {
const color = INCIDENT_COLORS[inc.type ?? "other"] ?? INCIDENT_COLORS.other;
return (
<button
key={inc.incident_id}
onClick={() => {
setDrawerOpen(false);
handleIncidentSelect(inc);
}}
className="w-full text-left border rounded px-2 py-1.5 text-xs font-mono"
style={{ borderColor: color + "55" }}
>
const label = (
<>
<span className="font-semibold" style={{ color }}>
{inc.type ?? "other"}
</span>
{" — "}
<span className="text-white">{inc.title ?? "Incident"}</span>
</button>
</>
);
if (inc.location_coords) {
return (
<button
key={inc.incident_id}
onClick={() => {
setDrawerOpen(false);
handleIncidentSelect(inc);
}}
className="w-full text-left border rounded px-2 py-1.5 text-xs font-mono"
style={{ borderColor: color + "55" }}
>
{label}
</button>
);
}
return (
<a
key={inc.incident_id}
href={`/incidents/${inc.incident_id}`}
className="block w-full text-left border rounded px-2 py-1.5 text-xs font-mono"
style={{ borderColor: color + "55" }}
>
{label}
</a>
);
})}
</div>