Skip to content

Commit b2d1c82

Browse files
committed
Enhances webhook inspector with event metadata
Introduces metadata and helpers to map technical event types to friendly names and descriptions Updates list and preview to show display names with help tooltips; unknown types are styled distinctly Improves UX with cursor hints and clearer event labeling
1 parent 1f78439 commit b2d1c82

File tree

3 files changed

+152
-4
lines changed

3 files changed

+152
-4
lines changed

src/components/WebhookInspector.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
.webhook-event-item.selected{background:#f7fbff}
1010
.webhook-event-item.new-event{animation:eventGlow 0.5s ease-out;box-shadow:0 0 0 2px #ff7a00}
1111
@keyframes eventGlow{0%{box-shadow:0 0 8px 4px rgba(255,122,0,0.6),0 0 0 2px #ff7a00}100%{box-shadow:0 0 0 0 rgba(255,122,0,0),0 0 0 2px #ff7a00}}
12-
.event-type{font-size:13px;color:#333}
12+
.event-type{font-size:13px;color:#333;cursor:help;position:relative}
13+
.event-type.unknown-event{color:#666;font-style:italic}
1314
.event-meta{font-size:12px;color:#777}
1415
.event-session-indicators{display:flex;gap:6px;margin-top:6px;align-items:center}
1516
.session-dot{width:10px;height:10px;border-radius:50%;border:1px solid rgba(0,0,0,0.1)}
1617
.no-events{padding:12px;color:#666}
1718
.webhook-inspector-preview{flex:1;padding:12px;overflow:hidden;min-width:0;display:flex;flex-direction:column}
1819
.webhook-inspector-preview > div{display:flex;flex-direction:column;flex:1;min-height:0}
1920
.preview-header{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:8px}
20-
.preview-title{margin:0;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21+
.preview-title{margin:0;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:help}
2122
.preview-time{color:#999;font-size:11px;flex-shrink:0}
2223
.preview-json{background:#fafafa;padding:12px;border-radius:6px;overflow:auto}
2324
.preview-empty{color:#666}

src/components/WebhookInspector.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MeasurementTilesView from './MeasurementTilesView';
55
import CourseInfoBanner from './CourseInfoBanner';
66
import { ShotData } from './ShotTrajectoryOverlay';
77
import { useActivitySessionState } from '../hooks/useActivitySessionState';
8+
import { getEventDisplayName, getEventDescription, hasEventMetadata } from '../utils/eventMetadata';
89

910
type EventItem = {
1011
id?: string;
@@ -679,7 +680,12 @@ const WebhookInspector: React.FC<Props> = ({ userPath, selectedDeviceId = null,
679680
className={`webhook-event-item ${selectedIndex === visibleIdx ? 'selected' : ''} ${isNew ? 'new-event' : ''}`}
680681
onClick={() => select(visibleIdx)}
681682
>
682-
<div className="event-type">{e.eventType}</div>
683+
<div
684+
className={`event-type ${!hasEventMetadata(e.eventType) ? 'unknown-event' : ''}`}
685+
title={getEventDescription(e.eventType) ? `${e.eventType}\n${getEventDescription(e.eventType)}` : e.eventType}
686+
>
687+
{getEventDisplayName(e.eventType)}
688+
</div>
683689
<div className="event-meta">{new Date(e.timestamp).toLocaleString()}</div>
684690
<div className="event-session-indicators">
685691
{customerColor && (
@@ -709,7 +715,14 @@ const WebhookInspector: React.FC<Props> = ({ userPath, selectedDeviceId = null,
709715
{selectedEvent ? (
710716
<div>
711717
<div className="preview-header">
712-
<h4 className="preview-title">{selectedEvent.eventType}</h4>
718+
<h4
719+
className="preview-title"
720+
title={getEventDescription(selectedEvent.eventType)
721+
? `${selectedEvent.eventType}\n${getEventDescription(selectedEvent.eventType)}`
722+
: selectedEvent.eventType}
723+
>
724+
{getEventDisplayName(selectedEvent.eventType)}
725+
</h4>
713726
<div className="preview-time">{new Date(selectedEvent.timestamp).toLocaleString()}</div>
714727
</div>
715728
{/* Display course information if available for this activity session */}

src/utils/eventMetadata.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Event metadata for webhook events
2+
// Maps technical event names to human-friendly names and descriptions
3+
4+
export interface EventMetadata {
5+
displayName: string;
6+
description: string;
7+
}
8+
9+
export const EVENT_METADATA: Record<string, EventMetadata> = {
10+
// Simulator Events
11+
'TPS.Simulator.ChangePlayer': {
12+
displayName: 'Change Player',
13+
description: 'Player has been switched or changed in the simulator session',
14+
},
15+
'TPS.Simulator.HoleCompleted': {
16+
displayName: 'Hole Completed',
17+
description: 'Player has finished playing the current hole',
18+
},
19+
'TPS.Simulator.ShotStarting': {
20+
displayName: 'Shot Starting',
21+
description: 'A shot is about to be taken',
22+
},
23+
'TPS.Simulator.ShotFinish': {
24+
displayName: 'Shot Finished',
25+
description: 'Shot has been completed with final trajectory data',
26+
},
27+
'TPS.Simulator.SessionStarted': {
28+
displayName: 'Session Started',
29+
description: 'New simulator session has been initiated',
30+
},
31+
'TPS.Simulator.SessionEnded': {
32+
displayName: 'Session Ended',
33+
description: 'Simulator session has been terminated',
34+
},
35+
36+
// Live Events
37+
'TPS.Live.OnStrokeCompletedEvent': {
38+
displayName: 'Stroke Completed',
39+
description: 'Ball strike has been detected and measured',
40+
},
41+
'TPS.Live.OnStrokeConditionChanged': {
42+
displayName: 'Stroke Condition Changed',
43+
description: 'Shot condition or state has been modified',
44+
},
45+
'TPS.Live.OnBallLandedEvent': {
46+
displayName: 'Ball Landed',
47+
description: 'Ball has landed and final position recorded',
48+
},
49+
'TPS.Live.OnCameraImageReceivedEvent': {
50+
displayName: 'Camera Image Received',
51+
description: 'Image captured from camera system',
52+
},
53+
54+
// Session Events
55+
'TPS.SessionInfo': {
56+
displayName: 'Session Info',
57+
description: 'Session information and configuration data',
58+
},
59+
'TPS.SessionStarted': {
60+
displayName: 'Session Started',
61+
description: 'New practice or play session has begun',
62+
},
63+
'TPS.SessionEnded': {
64+
displayName: 'Session Ended',
65+
description: 'Session has been completed or terminated',
66+
},
67+
68+
// Device Events
69+
'TPS.Device.Connected': {
70+
displayName: 'Device Connected',
71+
description: 'Device has successfully connected to the system',
72+
},
73+
'TPS.Device.Disconnected': {
74+
displayName: 'Device Disconnected',
75+
description: 'Device has been disconnected from the system',
76+
},
77+
'TPS.Device.StatusUpdate': {
78+
displayName: 'Device Status',
79+
description: 'Device status information has been updated',
80+
},
81+
82+
// Club Events
83+
'TPS.ClubRecognized': {
84+
displayName: 'Club Recognized',
85+
description: 'Golf club type has been identified',
86+
},
87+
'TPS.ClubChanged': {
88+
displayName: 'Club Changed',
89+
description: 'Player has switched to a different club',
90+
},
91+
92+
// Course Events
93+
'TPS.CourseLoaded': {
94+
displayName: 'Course Loaded',
95+
description: 'Golf course data has been loaded into the system',
96+
},
97+
'TPS.HoleChanged': {
98+
displayName: 'Hole Changed',
99+
description: 'Player has moved to a different hole',
100+
},
101+
102+
// Error Events
103+
'TPS.Error': {
104+
displayName: 'Error',
105+
description: 'An error has occurred in the system',
106+
},
107+
'TPS.Warning': {
108+
displayName: 'Warning',
109+
description: 'A warning condition has been detected',
110+
},
111+
};
112+
113+
/**
114+
* Get friendly display name for an event type
115+
* Falls back to original name if not found in metadata
116+
*/
117+
export function getEventDisplayName(eventType: string): string {
118+
return EVENT_METADATA[eventType]?.displayName || eventType;
119+
}
120+
121+
/**
122+
* Get description for an event type
123+
* Returns null if not found
124+
*/
125+
export function getEventDescription(eventType: string): string | null {
126+
return EVENT_METADATA[eventType]?.description || null;
127+
}
128+
129+
/**
130+
* Check if an event has metadata
131+
*/
132+
export function hasEventMetadata(eventType: string): boolean {
133+
return eventType in EVENT_METADATA;
134+
}

0 commit comments

Comments
 (0)