diff --git a/drb-frontend/app/incidents/[id]/page.tsx b/drb-frontend/app/incidents/[id]/page.tsx index 19638c7..01c961a 100644 --- a/drb-frontend/app/incidents/[id]/page.tsx +++ b/drb-frontend/app/incidents/[id]/page.tsx @@ -100,6 +100,7 @@ export default function IncidentDetailPage() { const displayTags = incident.tags.filter((t) => t !== "auto-generated"); const unitsActive = incident.units_active ?? incident.units ?? []; const unitsCleared = incident.units_cleared ?? []; + const vehicles = incident.vehicles ?? []; const active = incident.status === "active"; const visible = newestFirst.slice(0, earlierShown); @@ -213,11 +214,11 @@ export default function IncidentDetailPage() { - {incident.vehicles?.length > 0 && ( + {vehicles.length > 0 && (

Vehicles

- {incident.vehicles.map((v) => ( + {vehicles.map((v) => ( {v} ))}
diff --git a/drb-frontend/app/nodes/[id]/page.tsx b/drb-frontend/app/nodes/[id]/page.tsx index 0298663..9d0796a 100644 --- a/drb-frontend/app/nodes/[id]/page.tsx +++ b/drb-frontend/app/nodes/[id]/page.tsx @@ -60,7 +60,7 @@ function DiscordJoinModal({

Join Discord Voice

diff --git a/drb-frontend/app/nodes/page.tsx b/drb-frontend/app/nodes/page.tsx index f125cbe..7215834 100644 --- a/drb-frontend/app/nodes/page.tsx +++ b/drb-frontend/app/nodes/page.tsx @@ -42,7 +42,7 @@ export default function NodesPage() {
{pending.map((n) => (
setConfigNode(n)} className="cursor-pointer"> - +
))}
diff --git a/drb-frontend/app/trips/page.tsx b/drb-frontend/app/trips/page.tsx index 8ada768..f04a99f 100644 --- a/drb-frontend/app/trips/page.tsx +++ b/drb-frontend/app/trips/page.tsx @@ -22,7 +22,9 @@ function TripCard({ trip, isAdmin, onDelete }: { }) { const router = useRouter(); const today = new Date().toISOString().slice(0, 10); - const upcoming = trip.start_date >= today; + // Bucket and badge must agree: the list groups on end_date (page.tsx ~L176), + // so a trip isn't "Past" until it's over, not when it starts. + const upcoming = trip.end_date >= today; const attendeeCount = Object.keys(trip.attendees ?? {}).length; return ( @@ -97,10 +99,10 @@ function CreateModal({ onClose, onCreate }: { } return ( -
+

New Trip

diff --git a/drb-frontend/components/CallSpineEntry.tsx b/drb-frontend/components/CallSpineEntry.tsx index 27ad0c6..d939c1b 100644 --- a/drb-frontend/components/CallSpineEntry.tsx +++ b/drb-frontend/components/CallSpineEntry.tsx @@ -23,7 +23,7 @@ function fmtClock(s: number): string { return `${m}:${r.toString().padStart(2, "0")}`; } -function InlinePlayer({ callId, hasAudio }: { callId: string; hasAudio: boolean }) { +function InlinePlayer({ callId }: { callId: string }) { const [url, setUrl] = useState(null); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); @@ -32,8 +32,6 @@ function InlinePlayer({ callId, hasAudio }: { callId: string; hasAudio: boolean const [duration, setDuration] = useState(0); const audioRef = useRef(null); - if (!hasAudio) return null; - async function ensureUrl() { if (url || loading) return; setLoading(true); @@ -169,7 +167,7 @@ export function CallSpineEntry({ {hasAudio && (
- +
)} diff --git a/drb-frontend/components/NodeCard.tsx b/drb-frontend/components/NodeCard.tsx index 3d2335f..4b4a2b9 100644 --- a/drb-frontend/components/NodeCard.tsx +++ b/drb-frontend/components/NodeCard.tsx @@ -5,15 +5,20 @@ import type { NodeRecord, SystemRecord } from "@/lib/types"; interface Props { node: NodeRecord; system?: SystemRecord; + /** + * When false, the card renders without its `/nodes/[id]` Link wrapper so a + * parent click handler can take the interaction (pending nodes open the + * config modal instead of navigating). Defaults to true. + */ + linkToDetail?: boolean; } -export function NodeCard({ node, system }: Props) { +export function NodeCard({ node, system, linkToDetail = true }: Props) { const lastSeen = node.last_seen ? new Date(node.last_seen).toLocaleTimeString() : "never"; - return ( - + const body = (
@@ -58,6 +63,7 @@ export function NodeCard({ node, system }: Props) {
)}
- ); + + return linkToDetail ? {body} : body; } diff --git a/drb-frontend/components/NodeConfigModal.tsx b/drb-frontend/components/NodeConfigModal.tsx index f6c4bcc..8a58bcd 100644 --- a/drb-frontend/components/NodeConfigModal.tsx +++ b/drb-frontend/components/NodeConfigModal.tsx @@ -50,8 +50,8 @@ export function NodeConfigModal({ node, systems, onClose }: Props) { const selectedPreset = PRESETS.find((p) => p.value === preset); return ( -
-
+
+

Configure Node

{node.node_id} connected for the first time. diff --git a/drb-frontend/lib/types.ts b/drb-frontend/lib/types.ts index bc07a7a..679b1b5 100644 --- a/drb-frontend/lib/types.ts +++ b/drb-frontend/lib/types.ts @@ -143,8 +143,9 @@ export interface IncidentRecord { call_ids: string[]; system_ids: string[]; talkgroup_ids: string[]; - units: string[]; - vehicles: string[]; + /** Omitted on incident docs written before these fields existed. */ + units?: string[]; + vehicles?: string[]; /** Units currently believed on scene — maintained by incident_correlator.py `_attach`. */ units_active?: string[]; /** Units that reported clearing/back in service on this incident. */