@lvce-editor/chat-debug-view 4.1.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatDebugViewWorkerMain.js +1860 -782
- package/package.json +1 -1
|
@@ -955,36 +955,25 @@ const terminate = () => {
|
|
|
955
955
|
globalThis.close();
|
|
956
956
|
};
|
|
957
957
|
|
|
958
|
-
const {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
958
|
+
const createEventCategoryFilterOptions = () => {
|
|
959
|
+
return [{
|
|
960
|
+
label: 'All',
|
|
961
|
+
value: All
|
|
962
|
+
}, {
|
|
963
|
+
label: 'Tools',
|
|
964
|
+
value: Tools
|
|
965
|
+
}, {
|
|
966
|
+
label: 'Network',
|
|
967
|
+
value: Network
|
|
968
|
+
}, {
|
|
969
|
+
label: 'UI',
|
|
970
|
+
value: Ui
|
|
971
|
+
}, {
|
|
972
|
+
label: 'Stream',
|
|
973
|
+
value: Stream
|
|
974
|
+
}];
|
|
975
|
+
};
|
|
966
976
|
|
|
967
|
-
const All = 'all';
|
|
968
|
-
const Tools = 'tools';
|
|
969
|
-
const Network = 'network';
|
|
970
|
-
const Ui = 'ui';
|
|
971
|
-
const Stream = 'stream';
|
|
972
|
-
const options = [{
|
|
973
|
-
label: 'All',
|
|
974
|
-
value: All
|
|
975
|
-
}, {
|
|
976
|
-
label: 'Tools',
|
|
977
|
-
value: Tools
|
|
978
|
-
}, {
|
|
979
|
-
label: 'Network',
|
|
980
|
-
value: Network
|
|
981
|
-
}, {
|
|
982
|
-
label: 'UI',
|
|
983
|
-
value: Ui
|
|
984
|
-
}, {
|
|
985
|
-
label: 'Stream',
|
|
986
|
-
value: Stream
|
|
987
|
-
}];
|
|
988
977
|
const getEventCategoryFilterLabel = eventCategoryFilter => {
|
|
989
978
|
switch (eventCategoryFilter) {
|
|
990
979
|
case Network:
|
|
@@ -1000,6 +989,80 @@ const getEventCategoryFilterLabel = eventCategoryFilter => {
|
|
|
1000
989
|
}
|
|
1001
990
|
};
|
|
1002
991
|
|
|
992
|
+
const All = 'all';
|
|
993
|
+
const Tools = 'tools';
|
|
994
|
+
const Network = 'network';
|
|
995
|
+
const Ui = 'ui';
|
|
996
|
+
const Stream = 'stream';
|
|
997
|
+
|
|
998
|
+
const RE_SPACE = /\s+/;
|
|
999
|
+
const tokenToEventCategoryFilter = new Map([['@tools', Tools], ['@network', Network], ['@ui', Ui], ['@stream', Stream]]);
|
|
1000
|
+
const parseFilterValue = filterValue => {
|
|
1001
|
+
const normalizedFilter = filterValue.trim().toLowerCase();
|
|
1002
|
+
if (!normalizedFilter) {
|
|
1003
|
+
return {
|
|
1004
|
+
eventCategoryFilter: All,
|
|
1005
|
+
filterText: ''
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
const parts = normalizedFilter.split(RE_SPACE);
|
|
1009
|
+
const eventCategoryFilter = parts.map(part => tokenToEventCategoryFilter.get(part)).find(Boolean) || All;
|
|
1010
|
+
const filterText = parts.filter(part => !tokenToEventCategoryFilter.has(part)).join(' ');
|
|
1011
|
+
return {
|
|
1012
|
+
eventCategoryFilter,
|
|
1013
|
+
filterText
|
|
1014
|
+
};
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
const {
|
|
1018
|
+
get,
|
|
1019
|
+
getCommandIds,
|
|
1020
|
+
registerCommands,
|
|
1021
|
+
set,
|
|
1022
|
+
wrapCommand,
|
|
1023
|
+
wrapGetter
|
|
1024
|
+
} = create$1();
|
|
1025
|
+
|
|
1026
|
+
const Response = 'response';
|
|
1027
|
+
const Timing = 'timing';
|
|
1028
|
+
const detailTabs = [Response, Timing];
|
|
1029
|
+
const isDetailTab = value => {
|
|
1030
|
+
return value === Response || value === Timing;
|
|
1031
|
+
};
|
|
1032
|
+
const getDetailTabLabel = value => {
|
|
1033
|
+
if (value === Timing) {
|
|
1034
|
+
return 'Timing';
|
|
1035
|
+
}
|
|
1036
|
+
return 'Response';
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
const defaultTableWidth = 480;
|
|
1040
|
+
const minTableWidth = 240;
|
|
1041
|
+
const minDetailsWidth = 280;
|
|
1042
|
+
const sashWidth = 8;
|
|
1043
|
+
const viewPadding = 8;
|
|
1044
|
+
const timelineHorizontalPadding = 10;
|
|
1045
|
+
const horizontalPadding = viewPadding * 2;
|
|
1046
|
+
const leftPadding = viewPadding;
|
|
1047
|
+
const getMainWidth = width => {
|
|
1048
|
+
return Math.max(0, width - horizontalPadding);
|
|
1049
|
+
};
|
|
1050
|
+
const clampTableWidth = (width, tableWidth) => {
|
|
1051
|
+
const mainWidth = getMainWidth(width);
|
|
1052
|
+
const maxTableWidth = Math.max(0, mainWidth - minDetailsWidth - sashWidth);
|
|
1053
|
+
const minClampedTableWidth = Math.min(minTableWidth, maxTableWidth);
|
|
1054
|
+
return Math.max(minClampedTableWidth, Math.min(tableWidth, maxTableWidth));
|
|
1055
|
+
};
|
|
1056
|
+
const getDetailsWidth = (width, tableWidth) => {
|
|
1057
|
+
const mainWidth = getMainWidth(width);
|
|
1058
|
+
const clampedTableWidth = clampTableWidth(width, tableWidth);
|
|
1059
|
+
return Math.max(0, mainWidth - clampedTableWidth - sashWidth);
|
|
1060
|
+
};
|
|
1061
|
+
const getTableWidthFromClientX = (viewX, width, clientX) => {
|
|
1062
|
+
const nextTableWidth = clientX - viewX - leftPadding;
|
|
1063
|
+
return clampTableWidth(width, nextTableWidth);
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1003
1066
|
const createDefaultState = () => {
|
|
1004
1067
|
return {
|
|
1005
1068
|
assetDir: '',
|
|
@@ -1007,42 +1070,75 @@ const createDefaultState = () => {
|
|
|
1007
1070
|
dataBaseVersion: 2,
|
|
1008
1071
|
errorMessage: '',
|
|
1009
1072
|
eventCategoryFilter: All,
|
|
1073
|
+
eventCategoryFilterOptions: createEventCategoryFilterOptions(),
|
|
1010
1074
|
events: [],
|
|
1011
1075
|
eventStoreName: 'chat-view-events',
|
|
1012
1076
|
filterValue: '',
|
|
1013
1077
|
height: 0,
|
|
1078
|
+
indexedDbSupportOverride: undefined,
|
|
1014
1079
|
initial: false,
|
|
1015
1080
|
platform: 0,
|
|
1081
|
+
selectedDetailTab: Response,
|
|
1082
|
+
selectedEvent: null,
|
|
1083
|
+
selectedEventId: null,
|
|
1016
1084
|
selectedEventIndex: null,
|
|
1017
1085
|
sessionId: '',
|
|
1018
1086
|
sessionIdIndexName: 'sessionId',
|
|
1019
1087
|
showEventStreamFinishedEvents: false,
|
|
1020
1088
|
showInputEvents: false,
|
|
1021
1089
|
showResponsePartEvents: false,
|
|
1090
|
+
tableWidth: defaultTableWidth,
|
|
1022
1091
|
timelineEndSeconds: '',
|
|
1092
|
+
timelineSelectionActive: false,
|
|
1093
|
+
timelineSelectionAnchorSeconds: '',
|
|
1094
|
+
timelineSelectionFocusSeconds: '',
|
|
1023
1095
|
timelineStartSeconds: '',
|
|
1024
1096
|
uid: 0,
|
|
1025
1097
|
uri: '',
|
|
1026
|
-
useDevtoolsLayout:
|
|
1098
|
+
useDevtoolsLayout: true,
|
|
1027
1099
|
width: 0,
|
|
1028
1100
|
x: 0,
|
|
1029
1101
|
y: 0
|
|
1030
1102
|
};
|
|
1031
1103
|
};
|
|
1032
1104
|
|
|
1105
|
+
const validEventCategoryFilters = new Set([All, Network, Stream, Tools, Ui]);
|
|
1106
|
+
const getRestoredEventCategoryFilter = savedState => {
|
|
1107
|
+
if (typeof savedState.eventCategoryFilter === 'string' && validEventCategoryFilters.has(savedState.eventCategoryFilter)) {
|
|
1108
|
+
return savedState.eventCategoryFilter;
|
|
1109
|
+
}
|
|
1110
|
+
if (typeof savedState.filterValue === 'string') {
|
|
1111
|
+
return parseFilterValue(savedState.filterValue).eventCategoryFilter;
|
|
1112
|
+
}
|
|
1113
|
+
return All;
|
|
1114
|
+
};
|
|
1033
1115
|
const create = (uid, uri, x, y, width, height, platform, assetDir, sessionId = '', databaseName = 'lvce-chat-view-sessions', dataBaseVersion = 2, eventStoreName = 'chat-view-events', sessionIdIndexName = 'sessionId', savedState = {}) => {
|
|
1116
|
+
const defaultState = createDefaultState();
|
|
1117
|
+
const {
|
|
1118
|
+
filterValue,
|
|
1119
|
+
selectedEventId,
|
|
1120
|
+
tableWidth,
|
|
1121
|
+
timelineEndSeconds,
|
|
1122
|
+
timelineStartSeconds
|
|
1123
|
+
} = savedState;
|
|
1124
|
+
const restoredEventCategoryFilter = getRestoredEventCategoryFilter(savedState);
|
|
1034
1125
|
const state = {
|
|
1035
|
-
...
|
|
1036
|
-
...savedState,
|
|
1126
|
+
...defaultState,
|
|
1037
1127
|
assetDir,
|
|
1038
1128
|
databaseName,
|
|
1039
1129
|
dataBaseVersion,
|
|
1130
|
+
eventCategoryFilter: restoredEventCategoryFilter,
|
|
1040
1131
|
eventStoreName,
|
|
1132
|
+
filterValue: filterValue ?? defaultState.filterValue,
|
|
1041
1133
|
height,
|
|
1042
1134
|
initial: true,
|
|
1043
1135
|
platform,
|
|
1136
|
+
selectedEventId: selectedEventId ?? defaultState.selectedEventId,
|
|
1044
1137
|
sessionId,
|
|
1045
1138
|
sessionIdIndexName,
|
|
1139
|
+
tableWidth: tableWidth ?? defaultState.tableWidth,
|
|
1140
|
+
timelineEndSeconds: timelineEndSeconds ?? defaultState.timelineEndSeconds,
|
|
1141
|
+
timelineStartSeconds: timelineStartSeconds ?? defaultState.timelineStartSeconds,
|
|
1046
1142
|
uid,
|
|
1047
1143
|
uri,
|
|
1048
1144
|
width,
|
|
@@ -1057,7 +1153,7 @@ const RenderCss = 2;
|
|
|
1057
1153
|
const RenderIncremental = 3;
|
|
1058
1154
|
|
|
1059
1155
|
const diff = (oldState, newState) => {
|
|
1060
|
-
if (oldState.errorMessage !== newState.errorMessage || oldState.eventCategoryFilter !== newState.eventCategoryFilter || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.uid !== newState.uid) {
|
|
1156
|
+
if (oldState.errorMessage !== newState.errorMessage || oldState.eventCategoryFilter !== newState.eventCategoryFilter || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.tableWidth !== newState.tableWidth || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineSelectionActive !== newState.timelineSelectionActive || oldState.timelineSelectionAnchorSeconds !== newState.timelineSelectionAnchorSeconds || oldState.timelineSelectionFocusSeconds !== newState.timelineSelectionFocusSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.selectedDetailTab !== newState.selectedDetailTab || oldState.selectedEvent !== newState.selectedEvent || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.width !== newState.width || oldState.uid !== newState.uid) {
|
|
1061
1157
|
return [RenderIncremental, RenderCss];
|
|
1062
1158
|
}
|
|
1063
1159
|
return [];
|
|
@@ -1071,77 +1167,89 @@ const diff2 = uid => {
|
|
|
1071
1167
|
return diff(oldState, newState);
|
|
1072
1168
|
};
|
|
1073
1169
|
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
return null;
|
|
1170
|
+
const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
|
|
1171
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1172
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1078
1173
|
}
|
|
1079
|
-
return
|
|
1174
|
+
return true;
|
|
1080
1175
|
};
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
return state;
|
|
1085
|
-
}
|
|
1086
|
-
return {
|
|
1087
|
-
...state,
|
|
1088
|
-
selectedEventIndex
|
|
1089
|
-
};
|
|
1176
|
+
|
|
1177
|
+
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1178
|
+
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
|
|
1090
1179
|
};
|
|
1091
1180
|
|
|
1092
|
-
const startedEventType = 'tool-execution-started';
|
|
1093
|
-
const finishedEventType = 'tool-execution-finished';
|
|
1181
|
+
const startedEventType$1 = 'tool-execution-started';
|
|
1182
|
+
const finishedEventType$1 = 'tool-execution-finished';
|
|
1094
1183
|
const mergedEventType = 'tool-execution';
|
|
1184
|
+
|
|
1185
|
+
const isToolExecutionFinishedEvent = event => {
|
|
1186
|
+
return event.type === finishedEventType$1;
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
const isToolExecutionStartedEvent = event => {
|
|
1190
|
+
return event.type === startedEventType$1;
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
const getTimestamp$1 = value => {
|
|
1194
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
const getEndedTimestamp = event => {
|
|
1198
|
+
return getTimestamp$1(event.ended) ?? getTimestamp$1(event.endTime) ?? getTimestamp$1(event.endTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1095
1201
|
const eventStableIds = new WeakMap();
|
|
1096
|
-
|
|
1202
|
+
const eventStableIdState = {
|
|
1203
|
+
nextStableEventId: 1
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1097
1206
|
const getOrCreateStableEventId = event => {
|
|
1098
1207
|
const existingStableEventId = eventStableIds.get(event);
|
|
1099
1208
|
if (existingStableEventId) {
|
|
1100
1209
|
return existingStableEventId;
|
|
1101
1210
|
}
|
|
1102
|
-
const stableEventId = `event-${nextStableEventId++}`;
|
|
1211
|
+
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1103
1212
|
eventStableIds.set(event, stableEventId);
|
|
1104
1213
|
return stableEventId;
|
|
1105
1214
|
};
|
|
1106
|
-
|
|
1107
|
-
eventStableIds.set(event, stableEventId);
|
|
1108
|
-
};
|
|
1215
|
+
|
|
1109
1216
|
const getStartedTimestamp = event => {
|
|
1110
|
-
return event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp;
|
|
1111
|
-
};
|
|
1112
|
-
const getEndedTimestamp = event => {
|
|
1113
|
-
return event.ended ?? event.endTime ?? event.endTimestamp ?? event.timestamp;
|
|
1114
|
-
};
|
|
1115
|
-
const isToolExecutionStartedEvent = event => {
|
|
1116
|
-
return event.type === startedEventType;
|
|
1217
|
+
return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1117
1218
|
};
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1122
|
-
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1123
|
-
return startedEvent.toolName === finishedEvent.toolName;
|
|
1124
|
-
}
|
|
1125
|
-
return true;
|
|
1126
|
-
};
|
|
1127
|
-
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1128
|
-
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName(startedEvent, finishedEvent);
|
|
1219
|
+
|
|
1220
|
+
const setStableEventId = (event, stableEventId) => {
|
|
1221
|
+
eventStableIds.set(event, stableEventId);
|
|
1129
1222
|
};
|
|
1130
|
-
|
|
1223
|
+
|
|
1224
|
+
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent) => {
|
|
1225
|
+
const ended = getEndedTimestamp(finishedEvent);
|
|
1226
|
+
const {
|
|
1227
|
+
eventId
|
|
1228
|
+
} = startedEvent;
|
|
1229
|
+
const started = getStartedTimestamp(startedEvent);
|
|
1131
1230
|
const mergedEvent = {
|
|
1132
1231
|
...startedEvent,
|
|
1133
1232
|
...finishedEvent,
|
|
1134
|
-
ended:
|
|
1135
|
-
|
|
1233
|
+
...(ended === undefined ? {} : {
|
|
1234
|
+
ended
|
|
1235
|
+
}),
|
|
1236
|
+
...(eventId === undefined ? {} : {
|
|
1237
|
+
eventId
|
|
1238
|
+
}),
|
|
1239
|
+
...(started === undefined ? {} : {
|
|
1240
|
+
started
|
|
1241
|
+
}),
|
|
1136
1242
|
type: mergedEventType
|
|
1137
1243
|
};
|
|
1138
1244
|
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1139
1245
|
setStableEventId(mergedEvent, stableEventId);
|
|
1140
1246
|
return mergedEvent;
|
|
1141
1247
|
};
|
|
1248
|
+
|
|
1142
1249
|
const getStableEventId = event => {
|
|
1143
1250
|
return getOrCreateStableEventId(event);
|
|
1144
1251
|
};
|
|
1252
|
+
|
|
1145
1253
|
const collapseToolExecutionEvents = events => {
|
|
1146
1254
|
const collapsedEvents = [];
|
|
1147
1255
|
for (let i = 0; i < events.length; i++) {
|
|
@@ -1149,7 +1257,7 @@ const collapseToolExecutionEvents = events => {
|
|
|
1149
1257
|
if (isToolExecutionStartedEvent(event)) {
|
|
1150
1258
|
const nextEvent = events[i + 1];
|
|
1151
1259
|
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1152
|
-
collapsedEvents.push(mergeToolExecutionEvents(event, nextEvent));
|
|
1260
|
+
collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
|
|
1153
1261
|
i++;
|
|
1154
1262
|
continue;
|
|
1155
1263
|
}
|
|
@@ -1159,43 +1267,43 @@ const collapseToolExecutionEvents = events => {
|
|
|
1159
1267
|
return collapsedEvents;
|
|
1160
1268
|
};
|
|
1161
1269
|
|
|
1162
|
-
const
|
|
1163
|
-
return
|
|
1270
|
+
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1271
|
+
return events.filter(event => {
|
|
1272
|
+
if (!showInputEvents && event.type === 'handle-input') {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1276
|
+
return false;
|
|
1277
|
+
}
|
|
1278
|
+
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
// hide session creation events by default — not useful in the debug view
|
|
1282
|
+
if (event.type === 'chat-session-created') {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
return true;
|
|
1286
|
+
});
|
|
1164
1287
|
};
|
|
1165
1288
|
|
|
1166
|
-
const
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
filterText: ''
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
const parts = normalizedFilter.split(RE_SPACE);
|
|
1177
|
-
const eventCategoryFilter = parts.map(part => tokenToEventCategoryFilter.get(part)).find(Boolean) || All;
|
|
1178
|
-
const filterText = parts.filter(part => !tokenToEventCategoryFilter.has(part)).join(' ');
|
|
1179
|
-
return {
|
|
1180
|
-
eventCategoryFilter,
|
|
1181
|
-
filterText
|
|
1182
|
-
};
|
|
1289
|
+
const isNetworkEvent = event => {
|
|
1290
|
+
const normalizedType = event.type.toLowerCase();
|
|
1291
|
+
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1292
|
+
};
|
|
1293
|
+
|
|
1294
|
+
const isStreamEvent = event => {
|
|
1295
|
+
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1183
1296
|
};
|
|
1184
1297
|
|
|
1185
1298
|
const toolEventTypePrefix = 'tool-execution';
|
|
1186
1299
|
const isToolEvent = event => {
|
|
1187
1300
|
return event.type.startsWith(toolEventTypePrefix);
|
|
1188
1301
|
};
|
|
1189
|
-
|
|
1190
|
-
const normalizedType = event.type.toLowerCase();
|
|
1191
|
-
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1192
|
-
};
|
|
1302
|
+
|
|
1193
1303
|
const isUiEvent = event => {
|
|
1194
1304
|
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1195
1305
|
};
|
|
1196
|
-
|
|
1197
|
-
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1198
|
-
};
|
|
1306
|
+
|
|
1199
1307
|
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1200
1308
|
switch (eventCategoryFilter) {
|
|
1201
1309
|
case Network:
|
|
@@ -1210,24 +1318,7 @@ const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
|
1210
1318
|
return true;
|
|
1211
1319
|
}
|
|
1212
1320
|
};
|
|
1213
|
-
|
|
1214
|
-
return events.filter(event => {
|
|
1215
|
-
if (!showInputEvents && event.type === 'handle-input') {
|
|
1216
|
-
return false;
|
|
1217
|
-
}
|
|
1218
|
-
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1219
|
-
return false;
|
|
1220
|
-
}
|
|
1221
|
-
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1222
|
-
return false;
|
|
1223
|
-
}
|
|
1224
|
-
// hide session creation events by default — not useful in the debug view
|
|
1225
|
-
if (event.type === 'chat-session-created') {
|
|
1226
|
-
return false;
|
|
1227
|
-
}
|
|
1228
|
-
return true;
|
|
1229
|
-
});
|
|
1230
|
-
};
|
|
1321
|
+
|
|
1231
1322
|
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1232
1323
|
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1233
1324
|
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
@@ -1287,6 +1378,21 @@ const getEventsWithTime = events => {
|
|
|
1287
1378
|
}];
|
|
1288
1379
|
});
|
|
1289
1380
|
};
|
|
1381
|
+
const getTimelineDurationSeconds = events => {
|
|
1382
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1383
|
+
if (eventsWithTime.length === 0) {
|
|
1384
|
+
return 0;
|
|
1385
|
+
}
|
|
1386
|
+
const baseTime = eventsWithTime[0].time;
|
|
1387
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1388
|
+
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1389
|
+
};
|
|
1390
|
+
const getSelectionPercent = (value, durationSeconds) => {
|
|
1391
|
+
if (durationSeconds <= 0) {
|
|
1392
|
+
return 0;
|
|
1393
|
+
}
|
|
1394
|
+
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1395
|
+
};
|
|
1290
1396
|
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1291
1397
|
const parsedStart = parseTimelineSeconds(startValue);
|
|
1292
1398
|
const parsedEnd = parseTimelineSeconds(endValue);
|
|
@@ -1331,6 +1437,8 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1331
1437
|
durationSeconds: 0,
|
|
1332
1438
|
endSeconds: null,
|
|
1333
1439
|
hasSelection: false,
|
|
1440
|
+
selectionEndPercent: null,
|
|
1441
|
+
selectionStartPercent: null,
|
|
1334
1442
|
startSeconds: null
|
|
1335
1443
|
};
|
|
1336
1444
|
}
|
|
@@ -1350,6 +1458,8 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1350
1458
|
counts[index] += 1;
|
|
1351
1459
|
}
|
|
1352
1460
|
const maxCount = Math.max(...counts);
|
|
1461
|
+
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1462
|
+
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1353
1463
|
const buckets = counts.map((count, index) => {
|
|
1354
1464
|
const bucketStartMs = index * bucketDurationMs;
|
|
1355
1465
|
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
@@ -1369,235 +1479,87 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1369
1479
|
durationSeconds,
|
|
1370
1480
|
endSeconds: range.endSeconds,
|
|
1371
1481
|
hasSelection: range.hasSelection,
|
|
1482
|
+
selectionEndPercent,
|
|
1483
|
+
selectionStartPercent,
|
|
1372
1484
|
startSeconds: range.startSeconds
|
|
1373
1485
|
};
|
|
1374
1486
|
};
|
|
1375
1487
|
|
|
1376
|
-
|
|
1377
|
-
const EventCategoryFilter = 'eventCategoryFilter';
|
|
1378
|
-
const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
|
|
1379
|
-
const ShowInputEvents = 'showInputEvents';
|
|
1380
|
-
const ShowResponsePartEvents = 'showResponsePartEvents';
|
|
1381
|
-
const UseDevtoolsLayout = 'useDevtoolsLayout';
|
|
1382
|
-
const SelectedEventIndex = 'selectedEventIndex';
|
|
1383
|
-
const CloseDetails = 'closeDetails';
|
|
1384
|
-
const TimelineStartSeconds = 'timelineStartSeconds';
|
|
1385
|
-
const TimelineEndSeconds = 'timelineEndSeconds';
|
|
1386
|
-
const TimelineRangePreset = 'timelineRangePreset';
|
|
1488
|
+
// cspell:ignore IDBP
|
|
1387
1489
|
|
|
1388
|
-
const
|
|
1389
|
-
|
|
1390
|
-
|
|
1490
|
+
const startedEventType = 'tool-execution-started';
|
|
1491
|
+
const finishedEventType = 'tool-execution-finished';
|
|
1492
|
+
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1493
|
+
if (eventId < 1) {
|
|
1494
|
+
return undefined;
|
|
1495
|
+
}
|
|
1496
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1497
|
+
const index = store.index(sessionIdIndexName);
|
|
1498
|
+
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1499
|
+
if (keys.length < eventId) {
|
|
1500
|
+
return undefined;
|
|
1501
|
+
}
|
|
1502
|
+
const key = keys.at(-1);
|
|
1503
|
+
if (key === undefined) {
|
|
1504
|
+
return undefined;
|
|
1505
|
+
}
|
|
1506
|
+
const event = await store.get(key);
|
|
1507
|
+
return event;
|
|
1508
|
+
}
|
|
1509
|
+
const all = await store.getAll();
|
|
1510
|
+
const events = all.filter(event => event.sessionId === sessionId);
|
|
1511
|
+
return events[eventId - 1];
|
|
1391
1512
|
};
|
|
1392
|
-
const
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1513
|
+
const getTimestamp = value => {
|
|
1514
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1515
|
+
};
|
|
1516
|
+
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1517
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1518
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1398
1519
|
}
|
|
1399
|
-
|
|
1520
|
+
return true;
|
|
1521
|
+
};
|
|
1522
|
+
const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
|
|
1523
|
+
const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
|
|
1524
|
+
const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
|
|
1400
1525
|
return {
|
|
1401
|
-
|
|
1402
|
-
|
|
1526
|
+
...startedEvent,
|
|
1527
|
+
...finishedEvent,
|
|
1528
|
+
...(ended === undefined ? {} : {
|
|
1529
|
+
ended
|
|
1530
|
+
}),
|
|
1531
|
+
eventId,
|
|
1532
|
+
...(started === undefined ? {} : {
|
|
1533
|
+
started
|
|
1534
|
+
}),
|
|
1535
|
+
type: 'tool-execution'
|
|
1403
1536
|
};
|
|
1404
1537
|
};
|
|
1405
|
-
const
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
const getSelectedEventIndex = state => {
|
|
1410
|
-
const {
|
|
1411
|
-
selectedEventIndex
|
|
1412
|
-
} = state;
|
|
1413
|
-
if (selectedEventIndex === null) {
|
|
1414
|
-
return null;
|
|
1415
|
-
}
|
|
1416
|
-
const filteredEvents = getCurrentEvents(state);
|
|
1417
|
-
const selectedEvent = filteredEvents[selectedEventIndex];
|
|
1418
|
-
if (!selectedEvent) {
|
|
1419
|
-
return null;
|
|
1420
|
-
}
|
|
1421
|
-
const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
|
|
1422
|
-
if (newIndex === -1) {
|
|
1423
|
-
return null;
|
|
1424
|
-
}
|
|
1425
|
-
return newIndex;
|
|
1426
|
-
};
|
|
1427
|
-
const getPreservedSelectedEventIndex = (oldState, newState) => {
|
|
1428
|
-
const {
|
|
1429
|
-
selectedEventIndex
|
|
1430
|
-
} = oldState;
|
|
1431
|
-
if (selectedEventIndex === null) {
|
|
1432
|
-
return null;
|
|
1433
|
-
}
|
|
1434
|
-
const oldFilteredEvents = getCurrentEvents(oldState);
|
|
1435
|
-
const selectedEvent = oldFilteredEvents[selectedEventIndex];
|
|
1436
|
-
if (!selectedEvent) {
|
|
1437
|
-
return null;
|
|
1438
|
-
}
|
|
1439
|
-
const newFilteredEvents = getCurrentEvents(newState);
|
|
1440
|
-
const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
|
|
1441
|
-
if (newIndex === -1) {
|
|
1442
|
-
return null;
|
|
1443
|
-
}
|
|
1444
|
-
return newIndex;
|
|
1445
|
-
};
|
|
1446
|
-
const parseSelectedEventIndex = value => {
|
|
1447
|
-
const parsed = Number.parseInt(value, 10);
|
|
1448
|
-
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1449
|
-
return null;
|
|
1450
|
-
}
|
|
1451
|
-
return parsed;
|
|
1452
|
-
};
|
|
1453
|
-
const handleInput = (state, name, value, checked) => {
|
|
1454
|
-
if (name === Filter) {
|
|
1455
|
-
const nextState = {
|
|
1456
|
-
...state,
|
|
1457
|
-
filterValue: value
|
|
1458
|
-
};
|
|
1459
|
-
return {
|
|
1460
|
-
...nextState,
|
|
1461
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1462
|
-
};
|
|
1463
|
-
}
|
|
1464
|
-
if (name === EventCategoryFilter) {
|
|
1465
|
-
const nextState = {
|
|
1466
|
-
...state,
|
|
1467
|
-
eventCategoryFilter: value || All
|
|
1468
|
-
};
|
|
1469
|
-
return {
|
|
1470
|
-
...nextState,
|
|
1471
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1472
|
-
};
|
|
1473
|
-
}
|
|
1474
|
-
if (name === ShowEventStreamFinishedEvents) {
|
|
1475
|
-
const nextState = {
|
|
1476
|
-
...state,
|
|
1477
|
-
showEventStreamFinishedEvents: getBoolean(checked)
|
|
1478
|
-
};
|
|
1479
|
-
return {
|
|
1480
|
-
...nextState,
|
|
1481
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
if (name === ShowInputEvents) {
|
|
1485
|
-
const nextState = {
|
|
1486
|
-
...state,
|
|
1487
|
-
showInputEvents: getBoolean(checked)
|
|
1488
|
-
};
|
|
1489
|
-
return {
|
|
1490
|
-
...nextState,
|
|
1491
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
if (name === ShowResponsePartEvents) {
|
|
1495
|
-
const nextState = {
|
|
1496
|
-
...state,
|
|
1497
|
-
showResponsePartEvents: getBoolean(checked)
|
|
1498
|
-
};
|
|
1499
|
-
return {
|
|
1500
|
-
...nextState,
|
|
1501
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1502
|
-
};
|
|
1503
|
-
}
|
|
1504
|
-
if (name === UseDevtoolsLayout) {
|
|
1505
|
-
const useDevtoolsLayout = getBoolean(checked);
|
|
1506
|
-
return {
|
|
1507
|
-
...state,
|
|
1508
|
-
selectedEventIndex: useDevtoolsLayout ? getSelectedEventIndex(state) : null,
|
|
1509
|
-
useDevtoolsLayout
|
|
1510
|
-
};
|
|
1511
|
-
}
|
|
1512
|
-
if (name === SelectedEventIndex) {
|
|
1513
|
-
return {
|
|
1514
|
-
...state,
|
|
1515
|
-
selectedEventIndex: parseSelectedEventIndex(value)
|
|
1516
|
-
};
|
|
1517
|
-
}
|
|
1518
|
-
if (name === TimelineStartSeconds) {
|
|
1519
|
-
const nextState = {
|
|
1520
|
-
...state,
|
|
1521
|
-
timelineStartSeconds: value
|
|
1522
|
-
};
|
|
1523
|
-
return {
|
|
1524
|
-
...nextState,
|
|
1525
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1526
|
-
};
|
|
1538
|
+
const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
|
|
1539
|
+
const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
|
|
1540
|
+
if (!event) {
|
|
1541
|
+
return undefined;
|
|
1527
1542
|
}
|
|
1528
|
-
if (
|
|
1529
|
-
const nextState = {
|
|
1530
|
-
...state,
|
|
1531
|
-
timelineEndSeconds: value
|
|
1532
|
-
};
|
|
1543
|
+
if (summaryType !== 'tool-execution') {
|
|
1533
1544
|
return {
|
|
1534
|
-
...
|
|
1535
|
-
|
|
1545
|
+
...event,
|
|
1546
|
+
eventId
|
|
1536
1547
|
};
|
|
1537
1548
|
}
|
|
1538
|
-
if (
|
|
1539
|
-
const nextState = {
|
|
1540
|
-
...state,
|
|
1541
|
-
...parseTimelineRangePreset(value)
|
|
1542
|
-
};
|
|
1549
|
+
if (event.type !== startedEventType) {
|
|
1543
1550
|
return {
|
|
1544
|
-
...
|
|
1545
|
-
|
|
1551
|
+
...event,
|
|
1552
|
+
eventId
|
|
1546
1553
|
};
|
|
1547
1554
|
}
|
|
1548
|
-
|
|
1555
|
+
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1556
|
+
if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
|
|
1549
1557
|
return {
|
|
1550
|
-
...
|
|
1551
|
-
|
|
1558
|
+
...event,
|
|
1559
|
+
eventId
|
|
1552
1560
|
};
|
|
1553
1561
|
}
|
|
1554
|
-
return
|
|
1555
|
-
};
|
|
1556
|
-
|
|
1557
|
-
const getFailedToLoadMessage = sessionId => {
|
|
1558
|
-
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
1559
|
-
};
|
|
1560
|
-
|
|
1561
|
-
const ParseChatDebugUriErrorCode = {
|
|
1562
|
-
InvalidSessionId: 'invalid-session-id',
|
|
1563
|
-
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
1564
|
-
InvalidUriFormat: 'invalid-uri-format',
|
|
1565
|
-
MissingUri: 'missing-uri'
|
|
1566
|
-
};
|
|
1567
|
-
|
|
1568
|
-
const getInvalidUriMessage = (uri, code) => {
|
|
1569
|
-
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
1570
|
-
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
1571
|
-
}
|
|
1572
|
-
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
1573
|
-
};
|
|
1574
|
-
|
|
1575
|
-
const getSessionNotFoundMessage = sessionId => {
|
|
1576
|
-
return `No chat session found for sessionId "${sessionId}".`;
|
|
1577
|
-
};
|
|
1578
|
-
|
|
1579
|
-
const filterEventsBySessionId = (events, sessionId) => {
|
|
1580
|
-
return events.filter(event => event.sessionId === sessionId);
|
|
1581
|
-
};
|
|
1582
|
-
|
|
1583
|
-
// cspell:ignore IDBP
|
|
1584
|
-
|
|
1585
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1586
|
-
const getAllEvents = async store => {
|
|
1587
|
-
const all = await store.getAll();
|
|
1588
|
-
return all;
|
|
1589
|
-
};
|
|
1590
|
-
|
|
1591
|
-
// cspell:ignore IDBP
|
|
1592
|
-
|
|
1593
|
-
const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
|
|
1594
|
-
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1595
|
-
const index = store.index(sessionIdIndexName);
|
|
1596
|
-
const events = await index.getAll(sessionId);
|
|
1597
|
-
return filterEventsBySessionId(events, sessionId);
|
|
1598
|
-
}
|
|
1599
|
-
const all = await getAllEvents(store);
|
|
1600
|
-
return filterEventsBySessionId(all, sessionId);
|
|
1562
|
+
return mergeToolExecutionEvents(event, nextEvent, eventId);
|
|
1601
1563
|
};
|
|
1602
1564
|
|
|
1603
1565
|
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
@@ -1854,137 +1816,733 @@ replaceTraps(oldTraps => ({
|
|
|
1854
1816
|
}
|
|
1855
1817
|
}));
|
|
1856
1818
|
|
|
1819
|
+
const openDatabaseDependencies = {
|
|
1820
|
+
openDB: openDB
|
|
1821
|
+
};
|
|
1857
1822
|
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1858
|
-
return openDB(databaseName, dataBaseVersion);
|
|
1823
|
+
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1859
1824
|
};
|
|
1860
1825
|
|
|
1861
|
-
const
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1826
|
+
const loadSelectedEventDependencies = {
|
|
1827
|
+
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1828
|
+
openDatabase: openDatabase
|
|
1829
|
+
};
|
|
1830
|
+
const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
|
|
1831
|
+
const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
1866
1832
|
try {
|
|
1867
1833
|
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
1868
|
-
return
|
|
1834
|
+
return null;
|
|
1869
1835
|
}
|
|
1870
1836
|
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
1871
1837
|
const store = transaction.objectStore(eventStoreName);
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
}
|
|
1875
|
-
return getEventsBySessionId(store, sessionId, sessionIdIndexName);
|
|
1838
|
+
const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
|
|
1839
|
+
return event ?? null;
|
|
1876
1840
|
} finally {
|
|
1877
1841
|
database.close();
|
|
1878
1842
|
}
|
|
1879
1843
|
};
|
|
1880
1844
|
|
|
1881
|
-
const
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1845
|
+
const handleEventRowClickDependencies = {
|
|
1846
|
+
loadSelectedEvent: loadSelectedEvent
|
|
1847
|
+
};
|
|
1848
|
+
const getCurrentEvents$2 = state => {
|
|
1849
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1850
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1851
|
+
};
|
|
1852
|
+
const parseSelectedEventIndex$1 = value => {
|
|
1853
|
+
const parsed = Number.parseInt(value, 10);
|
|
1854
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1855
|
+
return null;
|
|
1890
1856
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
};
|
|
1857
|
+
return parsed;
|
|
1858
|
+
};
|
|
1859
|
+
const handleEventRowClick = async (state, value) => {
|
|
1860
|
+
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1861
|
+
if (selectedEventIndex === null) {
|
|
1862
|
+
return state;
|
|
1898
1863
|
}
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
sessionId = decodeURIComponent(encodedSessionId);
|
|
1903
|
-
} catch {
|
|
1864
|
+
const currentEvents = getCurrentEvents$2(state);
|
|
1865
|
+
const selectedEvent = currentEvents[selectedEventIndex];
|
|
1866
|
+
if (!selectedEvent) {
|
|
1904
1867
|
return {
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1868
|
+
...state,
|
|
1869
|
+
selectedEvent: null,
|
|
1870
|
+
selectedEventId: null,
|
|
1871
|
+
selectedEventIndex
|
|
1908
1872
|
};
|
|
1909
1873
|
}
|
|
1910
|
-
if (
|
|
1874
|
+
if (typeof selectedEvent.eventId !== 'number') {
|
|
1911
1875
|
return {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1876
|
+
...state,
|
|
1877
|
+
selectedEvent,
|
|
1878
|
+
selectedEventId: null,
|
|
1879
|
+
selectedEventIndex
|
|
1915
1880
|
};
|
|
1916
1881
|
}
|
|
1882
|
+
const selectedEventDetails = await handleEventRowClickDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
1917
1883
|
return {
|
|
1918
|
-
|
|
1919
|
-
|
|
1884
|
+
...state,
|
|
1885
|
+
selectedEvent: selectedEventDetails ?? selectedEvent,
|
|
1886
|
+
selectedEventId: selectedEvent.eventId,
|
|
1887
|
+
selectedEventIndex
|
|
1920
1888
|
};
|
|
1921
1889
|
};
|
|
1922
1890
|
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1891
|
+
const getBoolean = value => {
|
|
1892
|
+
return value === true || value === 'true' || value === 'on' || value === '1';
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
const Filter = 'filter';
|
|
1896
|
+
const EventCategoryFilter = 'eventCategoryFilter';
|
|
1897
|
+
const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
|
|
1898
|
+
const ShowInputEvents = 'showInputEvents';
|
|
1899
|
+
const ShowResponsePartEvents = 'showResponsePartEvents';
|
|
1900
|
+
const UseDevtoolsLayout = 'useDevtoolsLayout';
|
|
1901
|
+
const SelectedEventIndex = 'selectedEventIndex';
|
|
1902
|
+
const CloseDetails = 'closeDetails';
|
|
1903
|
+
const DetailTab = 'detailTab';
|
|
1904
|
+
const TimelineStartSeconds = 'timelineStartSeconds';
|
|
1905
|
+
const TimelineEndSeconds = 'timelineEndSeconds';
|
|
1906
|
+
const TimelineRangePreset = 'timelineRangePreset';
|
|
1907
|
+
|
|
1908
|
+
const getCurrentEvents$1 = state => {
|
|
1909
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1910
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1911
|
+
};
|
|
1912
|
+
const parseTimelineRangePreset = value => {
|
|
1913
|
+
if (!value) {
|
|
1933
1914
|
return {
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
events: [],
|
|
1937
|
-
initial: false,
|
|
1938
|
-
selectedEventIndex: null,
|
|
1939
|
-
sessionId: ''
|
|
1915
|
+
timelineEndSeconds: '',
|
|
1916
|
+
timelineStartSeconds: ''
|
|
1940
1917
|
};
|
|
1941
1918
|
}
|
|
1942
|
-
const
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1919
|
+
const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
|
|
1920
|
+
return {
|
|
1921
|
+
timelineEndSeconds,
|
|
1922
|
+
timelineStartSeconds
|
|
1923
|
+
};
|
|
1924
|
+
};
|
|
1925
|
+
const getEventIndexByStableId = (events, event) => {
|
|
1926
|
+
const stableEventId = getStableEventId(event);
|
|
1927
|
+
return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
|
|
1928
|
+
};
|
|
1929
|
+
const getSelectedEventIndex = state => {
|
|
1930
|
+
const {
|
|
1931
|
+
selectedEventIndex
|
|
1932
|
+
} = state;
|
|
1933
|
+
if (selectedEventIndex === null) {
|
|
1934
|
+
return null;
|
|
1935
|
+
}
|
|
1936
|
+
const filteredEvents = getCurrentEvents$1(state);
|
|
1937
|
+
const selectedEvent = filteredEvents[selectedEventIndex];
|
|
1938
|
+
if (!selectedEvent) {
|
|
1939
|
+
return null;
|
|
1940
|
+
}
|
|
1941
|
+
const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
|
|
1942
|
+
if (newIndex === -1) {
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
return newIndex;
|
|
1946
|
+
};
|
|
1947
|
+
const getPreservedSelectedEventIndex = (oldState, newState) => {
|
|
1948
|
+
const {
|
|
1949
|
+
selectedEventIndex
|
|
1950
|
+
} = oldState;
|
|
1951
|
+
if (selectedEventIndex === null) {
|
|
1952
|
+
return null;
|
|
1953
|
+
}
|
|
1954
|
+
const oldFilteredEvents = getCurrentEvents$1(oldState);
|
|
1955
|
+
const selectedEvent = oldFilteredEvents[selectedEventIndex];
|
|
1956
|
+
if (!selectedEvent) {
|
|
1957
|
+
return null;
|
|
1958
|
+
}
|
|
1959
|
+
const newFilteredEvents = getCurrentEvents$1(newState);
|
|
1960
|
+
const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
|
|
1961
|
+
if (newIndex === -1) {
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
return newIndex;
|
|
1965
|
+
};
|
|
1966
|
+
const parseSelectedEventIndex = value => {
|
|
1967
|
+
const parsed = Number.parseInt(value, 10);
|
|
1968
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
return parsed;
|
|
1972
|
+
};
|
|
1973
|
+
const withPreservedSelection = (state, nextState) => {
|
|
1974
|
+
const selectedEventIndex = getPreservedSelectedEventIndex(state, nextState);
|
|
1975
|
+
return {
|
|
1976
|
+
...nextState,
|
|
1977
|
+
selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
|
|
1978
|
+
selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
|
|
1979
|
+
selectedEventIndex
|
|
1980
|
+
};
|
|
1981
|
+
};
|
|
1982
|
+
const handleInput = (state, name, value, checked) => {
|
|
1983
|
+
if (name === Filter) {
|
|
1984
|
+
const nextState = {
|
|
1985
|
+
...state,
|
|
1986
|
+
filterValue: value
|
|
1987
|
+
};
|
|
1988
|
+
return withPreservedSelection(state, nextState);
|
|
1989
|
+
}
|
|
1990
|
+
if (name === EventCategoryFilter) {
|
|
1991
|
+
const nextState = {
|
|
1992
|
+
...state,
|
|
1993
|
+
eventCategoryFilter: value || All
|
|
1994
|
+
};
|
|
1995
|
+
return withPreservedSelection(state, nextState);
|
|
1996
|
+
}
|
|
1997
|
+
if (name === ShowEventStreamFinishedEvents) {
|
|
1998
|
+
const nextState = {
|
|
1999
|
+
...state,
|
|
2000
|
+
showEventStreamFinishedEvents: getBoolean(checked)
|
|
2001
|
+
};
|
|
2002
|
+
return withPreservedSelection(state, nextState);
|
|
2003
|
+
}
|
|
2004
|
+
if (name === ShowInputEvents) {
|
|
2005
|
+
const nextState = {
|
|
2006
|
+
...state,
|
|
2007
|
+
showInputEvents: getBoolean(checked)
|
|
2008
|
+
};
|
|
2009
|
+
return withPreservedSelection(state, nextState);
|
|
2010
|
+
}
|
|
2011
|
+
if (name === ShowResponsePartEvents) {
|
|
2012
|
+
const nextState = {
|
|
2013
|
+
...state,
|
|
2014
|
+
showResponsePartEvents: getBoolean(checked)
|
|
2015
|
+
};
|
|
2016
|
+
return withPreservedSelection(state, nextState);
|
|
2017
|
+
}
|
|
2018
|
+
if (name === UseDevtoolsLayout) {
|
|
2019
|
+
const useDevtoolsLayout = getBoolean(checked);
|
|
2020
|
+
const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex(state) : null;
|
|
2021
|
+
return {
|
|
2022
|
+
...state,
|
|
2023
|
+
selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
|
|
2024
|
+
selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
|
|
2025
|
+
selectedEventIndex,
|
|
2026
|
+
useDevtoolsLayout
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
if (name === SelectedEventIndex) {
|
|
2030
|
+
const selectedEventIndex = parseSelectedEventIndex(value);
|
|
2031
|
+
return {
|
|
2032
|
+
...state,
|
|
2033
|
+
selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
|
|
2034
|
+
selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
|
|
2035
|
+
selectedEventIndex
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
if (name === TimelineStartSeconds) {
|
|
2039
|
+
const nextState = {
|
|
2040
|
+
...state,
|
|
2041
|
+
timelineStartSeconds: value
|
|
2042
|
+
};
|
|
2043
|
+
return withPreservedSelection(state, nextState);
|
|
2044
|
+
}
|
|
2045
|
+
if (name === TimelineEndSeconds) {
|
|
2046
|
+
const nextState = {
|
|
2047
|
+
...state,
|
|
2048
|
+
timelineEndSeconds: value
|
|
2049
|
+
};
|
|
2050
|
+
return withPreservedSelection(state, nextState);
|
|
2051
|
+
}
|
|
2052
|
+
if (name === TimelineRangePreset) {
|
|
2053
|
+
const nextState = {
|
|
2054
|
+
...state,
|
|
2055
|
+
...parseTimelineRangePreset(value)
|
|
2056
|
+
};
|
|
2057
|
+
return withPreservedSelection(state, nextState);
|
|
2058
|
+
}
|
|
2059
|
+
if (name === CloseDetails) {
|
|
2060
|
+
return {
|
|
2061
|
+
...state,
|
|
2062
|
+
selectedEvent: null,
|
|
2063
|
+
selectedEventId: null,
|
|
2064
|
+
selectedEventIndex: null
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
if (name === DetailTab) {
|
|
2068
|
+
if (!isDetailTab(value)) {
|
|
2069
|
+
return state;
|
|
2070
|
+
}
|
|
2071
|
+
return {
|
|
2072
|
+
...state,
|
|
2073
|
+
selectedDetailTab: value
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
return state;
|
|
2077
|
+
};
|
|
2078
|
+
|
|
2079
|
+
const handleSashPointerDown = (state, eventX, eventY) => {
|
|
2080
|
+
return state;
|
|
2081
|
+
};
|
|
2082
|
+
|
|
2083
|
+
const handleSashPointerMove = (state, eventX, eventY) => {
|
|
2084
|
+
return {
|
|
2085
|
+
...state,
|
|
2086
|
+
tableWidth: getTableWidthFromClientX(state.x, state.width, eventX)
|
|
2087
|
+
};
|
|
2088
|
+
};
|
|
2089
|
+
|
|
2090
|
+
const handleSashPointerUp = (state, eventX, eventY) => {
|
|
2091
|
+
return state;
|
|
2092
|
+
};
|
|
2093
|
+
|
|
2094
|
+
const handleTableBodyContextMenu = state => {
|
|
2095
|
+
return state;
|
|
2096
|
+
};
|
|
2097
|
+
|
|
2098
|
+
const clearTimelineSelectionState = state => {
|
|
2099
|
+
return {
|
|
2100
|
+
...state,
|
|
2101
|
+
timelineSelectionActive: false,
|
|
2102
|
+
timelineSelectionAnchorSeconds: '',
|
|
2103
|
+
timelineSelectionFocusSeconds: ''
|
|
2104
|
+
};
|
|
2105
|
+
};
|
|
2106
|
+
|
|
2107
|
+
const handleTimelineDoubleClick = state => {
|
|
2108
|
+
const nextState = handleInput(state, TimelineRangePreset, '', false);
|
|
2109
|
+
return clearTimelineSelectionState(nextState);
|
|
2110
|
+
};
|
|
2111
|
+
|
|
2112
|
+
const getTimelineEvents = state => {
|
|
2113
|
+
return getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
const getTimelineLeft = state => {
|
|
2117
|
+
return state.x + viewPadding + timelineHorizontalPadding;
|
|
2118
|
+
};
|
|
2119
|
+
const getTimelineWidth = state => {
|
|
2120
|
+
return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
|
|
2121
|
+
};
|
|
2122
|
+
|
|
2123
|
+
const trailingZeroFractionRegex = /\.0+$/;
|
|
2124
|
+
const trailingFractionZeroRegex = /(\.\d*?)0+$/;
|
|
2125
|
+
const formatTimelinePresetValue = value => {
|
|
2126
|
+
return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
|
|
2127
|
+
};
|
|
2128
|
+
|
|
2129
|
+
const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
|
|
2130
|
+
if (timelineWidth <= 0) {
|
|
2131
|
+
return undefined;
|
|
2132
|
+
}
|
|
2133
|
+
const durationSeconds = getTimelineDurationSeconds(events);
|
|
2134
|
+
const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
|
|
2135
|
+
const ratio = relativeX / timelineWidth;
|
|
2136
|
+
return formatTimelinePresetValue(durationSeconds * ratio);
|
|
2137
|
+
};
|
|
2138
|
+
|
|
2139
|
+
const handleTimelinePointerDown = (state, eventX) => {
|
|
2140
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2141
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2142
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2143
|
+
const clientX = state.x + eventX;
|
|
2144
|
+
const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2145
|
+
if (seconds === undefined) {
|
|
2146
|
+
return state;
|
|
2147
|
+
}
|
|
2148
|
+
return {
|
|
2149
|
+
...state,
|
|
2150
|
+
timelineSelectionActive: true,
|
|
2151
|
+
timelineSelectionAnchorSeconds: seconds,
|
|
2152
|
+
timelineSelectionFocusSeconds: seconds
|
|
2153
|
+
};
|
|
2154
|
+
};
|
|
2155
|
+
|
|
2156
|
+
const handleTimelinePointerMove = (state, eventX) => {
|
|
2157
|
+
if (!state.timelineSelectionActive) {
|
|
2158
|
+
return state;
|
|
2159
|
+
}
|
|
2160
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2161
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2162
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2163
|
+
const clientX = state.x + eventX;
|
|
2164
|
+
const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2165
|
+
if (seconds === undefined) {
|
|
2166
|
+
return state;
|
|
2167
|
+
}
|
|
2168
|
+
return {
|
|
2169
|
+
...state,
|
|
2170
|
+
timelineSelectionFocusSeconds: seconds
|
|
2171
|
+
};
|
|
2172
|
+
};
|
|
2173
|
+
|
|
2174
|
+
const handleTimelinePointerUp = (state, eventX) => {
|
|
2175
|
+
if (!state.timelineSelectionActive) {
|
|
2176
|
+
return state;
|
|
2177
|
+
}
|
|
2178
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2179
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2180
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2181
|
+
const clientX = state.x + eventX;
|
|
2182
|
+
const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2183
|
+
if (focusSeconds === undefined) {
|
|
2184
|
+
return clearTimelineSelectionState(state);
|
|
2185
|
+
}
|
|
2186
|
+
const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
|
|
2187
|
+
const focus = Number.parseFloat(focusSeconds);
|
|
2188
|
+
const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
|
|
2189
|
+
const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
|
|
2190
|
+
const nextState = handleInput(state, TimelineRangePreset, `${startSeconds}:${endSeconds}`, false);
|
|
2191
|
+
return clearTimelineSelectionState(nextState);
|
|
2192
|
+
};
|
|
2193
|
+
|
|
2194
|
+
const getFailedToLoadMessage = sessionId => {
|
|
2195
|
+
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
const getIndexedDbNotSupportedMessage = () => {
|
|
2199
|
+
return 'Unable to load chat debug session: IndexedDB is not supported in this environment.';
|
|
2200
|
+
};
|
|
2201
|
+
|
|
2202
|
+
const ParseChatDebugUriErrorCode = {
|
|
2203
|
+
InvalidSessionId: 'invalid-session-id',
|
|
2204
|
+
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
2205
|
+
InvalidUriFormat: 'invalid-uri-format',
|
|
2206
|
+
MissingUri: 'missing-uri'
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
const getInvalidUriMessage = (uri, code) => {
|
|
2210
|
+
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
2211
|
+
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
2212
|
+
}
|
|
2213
|
+
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
2214
|
+
};
|
|
2215
|
+
|
|
2216
|
+
const getSessionNotFoundMessage = sessionId => {
|
|
2217
|
+
return `No chat session found for sessionId "${sessionId}".`;
|
|
2218
|
+
};
|
|
2219
|
+
|
|
2220
|
+
const filterEventsBySessionId = (events, sessionId) => {
|
|
2221
|
+
return events.filter(event => event.sessionId === sessionId);
|
|
2222
|
+
};
|
|
2223
|
+
|
|
2224
|
+
// cspell:ignore IDBP
|
|
2225
|
+
|
|
2226
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2227
|
+
const getAllEvents = async store => {
|
|
2228
|
+
const all = await store.getAll();
|
|
2229
|
+
return all;
|
|
2230
|
+
};
|
|
2231
|
+
|
|
2232
|
+
const getEndTime = event => {
|
|
2233
|
+
return event.ended ?? event.endTime ?? event.timestamp;
|
|
2234
|
+
};
|
|
2235
|
+
|
|
2236
|
+
const getStartTime = event => {
|
|
2237
|
+
return event.started ?? event.startTime ?? event.timestamp;
|
|
2238
|
+
};
|
|
2239
|
+
|
|
2240
|
+
const getDuration = event => {
|
|
2241
|
+
const explicitDuration = event.durationMs ?? event.duration;
|
|
2242
|
+
if (typeof explicitDuration === 'number' && Number.isFinite(explicitDuration)) {
|
|
2243
|
+
return explicitDuration;
|
|
2244
|
+
}
|
|
2245
|
+
const start = toTimeNumber(getStartTime(event));
|
|
2246
|
+
const end = toTimeNumber(getEndTime(event));
|
|
2247
|
+
if (start === undefined || end === undefined || !Number.isFinite(start) || !Number.isFinite(end)) {
|
|
2248
|
+
return 0;
|
|
2249
|
+
}
|
|
2250
|
+
return Math.max(0, end - start);
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
const isTimeValue = value => {
|
|
2254
|
+
return typeof value === 'number' || typeof value === 'string';
|
|
2255
|
+
};
|
|
2256
|
+
|
|
2257
|
+
const getLightweightEvent = (event, fallbackEventId) => {
|
|
2258
|
+
const startTime = getStartTime(event);
|
|
2259
|
+
const endTime = getEndTime(event);
|
|
2260
|
+
return {
|
|
2261
|
+
duration: getDuration(event),
|
|
2262
|
+
...(isTimeValue(endTime) ? {
|
|
2263
|
+
endTime
|
|
2264
|
+
} : {}),
|
|
2265
|
+
eventId: typeof event.eventId === 'number' ? event.eventId : fallbackEventId,
|
|
2266
|
+
...(isTimeValue(startTime) ? {
|
|
2267
|
+
startTime
|
|
2268
|
+
} : {}),
|
|
2269
|
+
type: event.type
|
|
2270
|
+
};
|
|
2271
|
+
};
|
|
2272
|
+
|
|
2273
|
+
// cspell:ignore IDBP
|
|
2274
|
+
|
|
2275
|
+
const toLightweightEvents = events => {
|
|
2276
|
+
const eventsWithIds = events.map((event, index) => {
|
|
2277
|
+
return {
|
|
2278
|
+
...event,
|
|
2279
|
+
eventId: index + 1
|
|
2280
|
+
};
|
|
2281
|
+
});
|
|
2282
|
+
return collapseToolExecutionEvents(eventsWithIds).map((event, index) => getLightweightEvent(event, index + 1));
|
|
2283
|
+
};
|
|
2284
|
+
const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
|
|
2285
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
2286
|
+
const index = store.index(sessionIdIndexName);
|
|
2287
|
+
const events = await index.getAll(sessionId);
|
|
2288
|
+
return toLightweightEvents(filterEventsBySessionId(events, sessionId));
|
|
2289
|
+
}
|
|
2290
|
+
const all = await getAllEvents(store);
|
|
2291
|
+
return toLightweightEvents(filterEventsBySessionId(all, sessionId));
|
|
2292
|
+
};
|
|
2293
|
+
|
|
2294
|
+
let indexedDbSupportOverride;
|
|
2295
|
+
const getIndexedDbSupportOverride = () => {
|
|
2296
|
+
return indexedDbSupportOverride;
|
|
2297
|
+
};
|
|
2298
|
+
const setIndexedDbSupportOverride = supported => {
|
|
2299
|
+
indexedDbSupportOverride = supported;
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
const isIndexedDbSupported = indexedDbSupportOverride => {
|
|
2303
|
+
if (typeof indexedDbSupportOverride === 'boolean') {
|
|
2304
|
+
return indexedDbSupportOverride;
|
|
2305
|
+
}
|
|
2306
|
+
const override = getIndexedDbSupportOverride();
|
|
2307
|
+
if (typeof override === 'boolean') {
|
|
2308
|
+
return override;
|
|
2309
|
+
}
|
|
2310
|
+
return globalThis.indexedDB !== undefined;
|
|
2311
|
+
};
|
|
2312
|
+
|
|
2313
|
+
const listChatViewEventsDependencies = {
|
|
2314
|
+
getEventsBySessionId: getEventsBySessionId,
|
|
2315
|
+
openDatabase: openDatabase
|
|
2316
|
+
};
|
|
2317
|
+
const listChatViewEvents = async (sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride) => {
|
|
2318
|
+
if (!isIndexedDbSupported(indexedDbSupportOverride)) {
|
|
2319
|
+
return {
|
|
2320
|
+
type: 'not-supported'
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
try {
|
|
2324
|
+
const database = await listChatViewEventsDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
2325
|
+
try {
|
|
2326
|
+
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
2327
|
+
return {
|
|
2328
|
+
events: [],
|
|
2329
|
+
type: 'success'
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
2333
|
+
const store = transaction.objectStore(eventStoreName);
|
|
2334
|
+
if (!sessionId) {
|
|
2335
|
+
return {
|
|
2336
|
+
events: [],
|
|
2337
|
+
type: 'success'
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
const events = await listChatViewEventsDependencies.getEventsBySessionId(store, sessionId, sessionIdIndexName);
|
|
2341
|
+
return {
|
|
2342
|
+
events,
|
|
2343
|
+
type: 'success'
|
|
2344
|
+
};
|
|
2345
|
+
} finally {
|
|
2346
|
+
database.close();
|
|
2347
|
+
}
|
|
2348
|
+
} catch (error) {
|
|
2349
|
+
return {
|
|
2350
|
+
error,
|
|
2351
|
+
type: 'error'
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
|
|
2356
|
+
const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
|
|
2357
|
+
const invalidSessionIdPattern = /[/?#]/;
|
|
2358
|
+
const parseChatDebugUri = uri => {
|
|
2359
|
+
if (!uri) {
|
|
2360
|
+
return {
|
|
2361
|
+
code: ParseChatDebugUriErrorCode.MissingUri,
|
|
2362
|
+
message: 'Missing URI',
|
|
2363
|
+
type: 'error'
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
const match = uri.match(chatDebugUriPattern);
|
|
2367
|
+
if (!match) {
|
|
2368
|
+
return {
|
|
2369
|
+
code: ParseChatDebugUriErrorCode.InvalidUriFormat,
|
|
2370
|
+
message: 'Invalid URI format',
|
|
2371
|
+
type: 'error'
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
const encodedSessionId = match[1];
|
|
2375
|
+
let sessionId;
|
|
2376
|
+
try {
|
|
2377
|
+
sessionId = decodeURIComponent(encodedSessionId);
|
|
2378
|
+
} catch {
|
|
2379
|
+
return {
|
|
2380
|
+
code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
|
|
2381
|
+
message: 'Invalid URI encoding',
|
|
2382
|
+
type: 'error'
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
|
|
2386
|
+
return {
|
|
2387
|
+
code: ParseChatDebugUriErrorCode.InvalidSessionId,
|
|
2388
|
+
message: 'Invalid session id',
|
|
2389
|
+
type: 'error'
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
return {
|
|
2393
|
+
sessionId,
|
|
2394
|
+
type: 'success'
|
|
2395
|
+
};
|
|
2396
|
+
};
|
|
2397
|
+
|
|
2398
|
+
const loadEventsDependencies = {
|
|
2399
|
+
listChatViewEvents: listChatViewEvents,
|
|
2400
|
+
loadSelectedEvent: loadSelectedEvent
|
|
2401
|
+
};
|
|
2402
|
+
const getCurrentEvents = state => {
|
|
2403
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
2404
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
2405
|
+
};
|
|
2406
|
+
const restoreSelectedEvent = async state => {
|
|
2407
|
+
if (state.selectedEventId === null) {
|
|
2408
|
+
return {
|
|
2409
|
+
...state,
|
|
2410
|
+
selectedEvent: null,
|
|
2411
|
+
selectedEventIndex: null
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
const currentEvents = getCurrentEvents(state);
|
|
2415
|
+
const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
|
|
2416
|
+
if (selectedEventIndex === -1) {
|
|
2417
|
+
return {
|
|
2418
|
+
...state,
|
|
2419
|
+
selectedEvent: null,
|
|
2420
|
+
selectedEventId: null,
|
|
2421
|
+
selectedEventIndex: null
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
const selectedEvent = currentEvents[selectedEventIndex];
|
|
2425
|
+
if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
|
|
1957
2426
|
return {
|
|
1958
2427
|
...state,
|
|
1959
|
-
|
|
1960
|
-
|
|
2428
|
+
selectedEvent: null,
|
|
2429
|
+
selectedEventId: null,
|
|
2430
|
+
selectedEventIndex: null
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
2434
|
+
return {
|
|
2435
|
+
...state,
|
|
2436
|
+
selectedEvent: selectedEventDetails,
|
|
2437
|
+
selectedEventId: selectedEvent.eventId,
|
|
2438
|
+
selectedEventIndex
|
|
2439
|
+
};
|
|
2440
|
+
};
|
|
2441
|
+
const getStateWithInvalidUri = state => {
|
|
2442
|
+
const parsed = parseChatDebugUri(state.uri);
|
|
2443
|
+
if (parsed.type !== 'error') {
|
|
2444
|
+
return state;
|
|
2445
|
+
}
|
|
2446
|
+
return {
|
|
2447
|
+
...state,
|
|
2448
|
+
errorMessage: getInvalidUriMessage(state.uri, parsed.code),
|
|
2449
|
+
events: [],
|
|
2450
|
+
initial: false,
|
|
2451
|
+
selectedEvent: null,
|
|
2452
|
+
selectedEventId: null,
|
|
2453
|
+
selectedEventIndex: null,
|
|
2454
|
+
sessionId: ''
|
|
2455
|
+
};
|
|
2456
|
+
};
|
|
2457
|
+
const getSessionIdFromUri = state => {
|
|
2458
|
+
const parsed = parseChatDebugUri(state.uri);
|
|
2459
|
+
if (parsed.type === 'error') {
|
|
2460
|
+
return undefined;
|
|
2461
|
+
}
|
|
2462
|
+
return parsed.sessionId;
|
|
2463
|
+
};
|
|
2464
|
+
const loadEventsForSessionId = async (state, sessionId) => {
|
|
2465
|
+
const {
|
|
2466
|
+
databaseName,
|
|
2467
|
+
dataBaseVersion,
|
|
2468
|
+
eventStoreName,
|
|
2469
|
+
indexedDbSupportOverride,
|
|
2470
|
+
sessionIdIndexName
|
|
2471
|
+
} = state;
|
|
2472
|
+
const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride);
|
|
2473
|
+
if (result.type === 'not-supported') {
|
|
2474
|
+
return {
|
|
2475
|
+
...state,
|
|
2476
|
+
errorMessage: getIndexedDbNotSupportedMessage(),
|
|
2477
|
+
events: [],
|
|
1961
2478
|
initial: false,
|
|
2479
|
+
selectedEvent: null,
|
|
2480
|
+
selectedEventId: null,
|
|
1962
2481
|
selectedEventIndex: null,
|
|
1963
2482
|
sessionId
|
|
1964
2483
|
};
|
|
1965
|
-
}
|
|
2484
|
+
}
|
|
2485
|
+
if (result.type === 'error') {
|
|
1966
2486
|
return {
|
|
1967
2487
|
...state,
|
|
1968
2488
|
errorMessage: getFailedToLoadMessage(sessionId),
|
|
1969
2489
|
events: [],
|
|
1970
2490
|
initial: false,
|
|
2491
|
+
selectedEvent: null,
|
|
2492
|
+
selectedEventId: null,
|
|
1971
2493
|
selectedEventIndex: null,
|
|
1972
2494
|
sessionId
|
|
1973
2495
|
};
|
|
1974
2496
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2497
|
+
const {
|
|
2498
|
+
events
|
|
2499
|
+
} = result;
|
|
2500
|
+
if (events.length === 0) {
|
|
2501
|
+
return {
|
|
2502
|
+
...state,
|
|
2503
|
+
errorMessage: getSessionNotFoundMessage(sessionId),
|
|
2504
|
+
events: [],
|
|
2505
|
+
initial: false,
|
|
2506
|
+
selectedEvent: null,
|
|
2507
|
+
selectedEventId: null,
|
|
2508
|
+
selectedEventIndex: null,
|
|
2509
|
+
sessionId
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
const nextState = {
|
|
1980
2513
|
...state,
|
|
1981
2514
|
errorMessage: '',
|
|
1982
2515
|
events,
|
|
1983
2516
|
initial: false,
|
|
1984
|
-
|
|
2517
|
+
sessionId
|
|
1985
2518
|
};
|
|
2519
|
+
return restoreSelectedEvent(nextState);
|
|
2520
|
+
};
|
|
2521
|
+
const loadEventsFromUri = async state => {
|
|
2522
|
+
const sessionId = getSessionIdFromUri(state);
|
|
2523
|
+
if (!sessionId) {
|
|
2524
|
+
return getStateWithInvalidUri(state);
|
|
2525
|
+
}
|
|
2526
|
+
return loadEventsForSessionId(state, sessionId);
|
|
2527
|
+
};
|
|
2528
|
+
const refreshEvents = async state => {
|
|
2529
|
+
const sessionId = state.sessionId || getSessionIdFromUri(state);
|
|
2530
|
+
if (!sessionId) {
|
|
2531
|
+
return getStateWithInvalidUri(state);
|
|
2532
|
+
}
|
|
2533
|
+
return loadEventsForSessionId(state, sessionId);
|
|
2534
|
+
};
|
|
2535
|
+
|
|
2536
|
+
const loadContent = async state => {
|
|
2537
|
+
return loadEventsFromUri(state);
|
|
1986
2538
|
};
|
|
1987
2539
|
|
|
2540
|
+
const refresh = async state => {
|
|
2541
|
+
return refreshEvents(state);
|
|
2542
|
+
};
|
|
2543
|
+
|
|
2544
|
+
const ClientX = 'event.clientX';
|
|
2545
|
+
const ClientY = 'event.clientY';
|
|
1988
2546
|
const TargetChecked = 'event.target.checked';
|
|
1989
2547
|
const TargetName = 'event.target.name';
|
|
1990
2548
|
const TargetValue = 'event.target.value';
|
|
@@ -1993,15 +2551,21 @@ const SetCss = 'Viewlet.setCss';
|
|
|
1993
2551
|
const SetDom2 = 'Viewlet.setDom2';
|
|
1994
2552
|
const SetPatches = 'Viewlet.setPatches';
|
|
1995
2553
|
|
|
1996
|
-
const getCss =
|
|
2554
|
+
const getCss = state => {
|
|
2555
|
+
const tableWidth = clampTableWidth(state.width, state.tableWidth);
|
|
2556
|
+
const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
|
|
1997
2557
|
return `
|
|
1998
2558
|
.ChatDebugView {
|
|
1999
|
-
|
|
2559
|
+
--ChatDebugViewDetailsWidth: ${detailsWidth}px;
|
|
2560
|
+
--ChatDebugViewSashWidth: ${sashWidth}px;
|
|
2561
|
+
--ChatDebugViewTableWidth: ${tableWidth}px;
|
|
2562
|
+
padding: ${viewPadding}px;
|
|
2000
2563
|
display: flex;
|
|
2001
2564
|
flex-direction: column;
|
|
2002
2565
|
height: 100%;
|
|
2003
2566
|
box-sizing: border-box;
|
|
2004
2567
|
gap: 8px;
|
|
2568
|
+
contain: strict;
|
|
2005
2569
|
}
|
|
2006
2570
|
|
|
2007
2571
|
.ChatDebugView--devtools {
|
|
@@ -2013,44 +2577,61 @@ const getCss = () => {
|
|
|
2013
2577
|
align-items: center;
|
|
2014
2578
|
gap: 12px;
|
|
2015
2579
|
flex-wrap: wrap;
|
|
2580
|
+
contain: content;
|
|
2016
2581
|
}
|
|
2017
2582
|
|
|
2018
|
-
.ChatDebugViewTop
|
|
2019
|
-
|
|
2583
|
+
.ChatDebugViewTop--devtools {
|
|
2584
|
+
align-items: stretch;
|
|
2020
2585
|
}
|
|
2021
2586
|
|
|
2022
|
-
.
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2587
|
+
.ChatDebugViewFilterInput {
|
|
2588
|
+
flex: 1;
|
|
2589
|
+
min-width: 0;
|
|
2590
|
+
max-width: 500px;
|
|
2591
|
+
contain: content;
|
|
2027
2592
|
}
|
|
2028
2593
|
|
|
2029
|
-
.
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2594
|
+
.ChatDebugViewFilterInput--devtools {
|
|
2595
|
+
flex: 0 1 80px;
|
|
2596
|
+
width: 100%;
|
|
2597
|
+
max-width: 80px;
|
|
2033
2598
|
}
|
|
2034
2599
|
|
|
2035
2600
|
.ChatDebugViewQuickFilterPill {
|
|
2036
|
-
display:
|
|
2601
|
+
display: flex;
|
|
2037
2602
|
align-items: center;
|
|
2038
2603
|
justify-content: center;
|
|
2604
|
+
min-height: 22px;
|
|
2605
|
+
padding: 0 10px;
|
|
2606
|
+
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2607
|
+
border-radius: 999px;
|
|
2608
|
+
cursor: pointer;
|
|
2609
|
+
white-space: nowrap;
|
|
2610
|
+
transition:
|
|
2611
|
+
background 120ms ease-out,
|
|
2612
|
+
border-color 120ms ease-out,
|
|
2613
|
+
color 120ms ease-out,
|
|
2614
|
+
transform 120ms ease-out;
|
|
2615
|
+
contain: content;
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
.ChatDebugViewQuickFilterPill:not(.ChatDebugViewQuickFilterPillSelected):hover {
|
|
2619
|
+
border-color: var(--vscode-focusBorder, #007fd4);
|
|
2620
|
+
background: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 82%, transparent 18%);
|
|
2621
|
+
color: var(--vscode-list-hoverForeground, inherit);
|
|
2622
|
+
transform: translateY(-1px);
|
|
2039
2623
|
}
|
|
2040
2624
|
|
|
2041
2625
|
|
|
2042
2626
|
.ChatDebugViewQuickFilters {
|
|
2043
2627
|
display: flex;
|
|
2628
|
+
align-items: center;
|
|
2044
2629
|
gap: 8px;
|
|
2045
2630
|
justify-content: center;
|
|
2046
2631
|
min-height: 28px;
|
|
2047
|
-
padding: 0 12px;
|
|
2048
|
-
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2049
|
-
border-radius: 999px;
|
|
2050
|
-
background: var(--vscode-editorWidget-background, transparent);
|
|
2051
|
-
cursor: pointer;
|
|
2052
2632
|
font-size: 12px;
|
|
2053
2633
|
line-height: 1;
|
|
2634
|
+
contain: content;
|
|
2054
2635
|
}
|
|
2055
2636
|
|
|
2056
2637
|
.ChatDebugViewQuickFilterPillSelected {
|
|
@@ -2063,6 +2644,7 @@ const getCss = () => {
|
|
|
2063
2644
|
position: absolute;
|
|
2064
2645
|
opacity: 0;
|
|
2065
2646
|
pointer-events: none;
|
|
2647
|
+
contain: content;
|
|
2066
2648
|
}
|
|
2067
2649
|
|
|
2068
2650
|
.ChatDebugViewEvents {
|
|
@@ -2073,14 +2655,10 @@ const getCss = () => {
|
|
|
2073
2655
|
min-height: 0;
|
|
2074
2656
|
scrollbar-width: thin;
|
|
2075
2657
|
scrollbar-color: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4)) transparent;
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
.ChatDebugViewEvents--timeline {
|
|
2079
|
-
gap: 0;
|
|
2658
|
+
contain: strict;
|
|
2080
2659
|
}
|
|
2081
2660
|
|
|
2082
2661
|
.ChatDebugView--devtools .ChatDebugViewEvents {
|
|
2083
|
-
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2084
2662
|
border-radius: 6px;
|
|
2085
2663
|
margin-bottom: 0;
|
|
2086
2664
|
overflow: hidden;
|
|
@@ -2092,21 +2670,66 @@ const getCss = () => {
|
|
|
2092
2670
|
|
|
2093
2671
|
.ChatDebugViewDevtoolsMain {
|
|
2094
2672
|
display: flex;
|
|
2095
|
-
flex-
|
|
2673
|
+
flex-direction: column;
|
|
2674
|
+
flex: 1;
|
|
2096
2675
|
align-items: stretch;
|
|
2097
|
-
gap:
|
|
2676
|
+
gap: 0;
|
|
2677
|
+
min-width: 0;
|
|
2678
|
+
min-height: 0;
|
|
2679
|
+
contain: strict;
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
.ChatDebugViewDevtoolsMain > .ChatDebugViewTimeline {
|
|
2683
|
+
flex: 0 0 auto;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
.ChatDebugViewDevtoolsSplit {
|
|
2687
|
+
display: flex;
|
|
2688
|
+
flex: 1;
|
|
2689
|
+
align-items: stretch;
|
|
2690
|
+
gap: 0;
|
|
2098
2691
|
min-width: 0;
|
|
2099
2692
|
min-height: 0;
|
|
2100
2693
|
overflow: hidden;
|
|
2694
|
+
contain: strict;
|
|
2101
2695
|
}
|
|
2102
2696
|
|
|
2103
|
-
.
|
|
2104
|
-
flex:
|
|
2697
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents {
|
|
2698
|
+
flex: 0 1 var(--ChatDebugViewTableWidth);
|
|
2105
2699
|
min-width: 0;
|
|
2106
2700
|
}
|
|
2107
2701
|
|
|
2108
|
-
.
|
|
2109
|
-
flex:
|
|
2702
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents.ChatDebugViewEventsFullWidth {
|
|
2703
|
+
flex: 1 1 100%;
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewDetails {
|
|
2707
|
+
border-left: 0;
|
|
2708
|
+
border-top-left-radius: 0;
|
|
2709
|
+
border-bottom-left-radius: 0;
|
|
2710
|
+
flex: 1;
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
.ChatDebugViewSash {
|
|
2714
|
+
flex: 0 0 var(--ChatDebugViewSashWidth);
|
|
2715
|
+
position: relative;
|
|
2716
|
+
cursor: col-resize;
|
|
2717
|
+
display: flex;
|
|
2718
|
+
justify-content: center;
|
|
2719
|
+
min-height: 0;
|
|
2720
|
+
contain: strict;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
.ChatDebugViewSashLine {
|
|
2724
|
+
width: 1px;
|
|
2725
|
+
height: 100%;
|
|
2726
|
+
background: var(--vscode-editorWidget-border, #454545);
|
|
2727
|
+
pointer-events: none;
|
|
2728
|
+
contain: strict;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
.ChatDebugViewSash:hover .ChatDebugViewSashLine {
|
|
2732
|
+
background: var(--vscode-focusBorder, #007fd4);
|
|
2110
2733
|
}
|
|
2111
2734
|
|
|
2112
2735
|
.ChatDebugViewTable {
|
|
@@ -2114,33 +2737,32 @@ const getCss = () => {
|
|
|
2114
2737
|
flex-direction: column;
|
|
2115
2738
|
min-height: 0;
|
|
2116
2739
|
flex: 1 1 auto;
|
|
2740
|
+
contain: strict;
|
|
2117
2741
|
}
|
|
2118
2742
|
|
|
2119
2743
|
.ChatDebugViewTimeline {
|
|
2120
2744
|
display: flex;
|
|
2121
2745
|
flex-direction: column;
|
|
2122
|
-
gap:
|
|
2123
|
-
padding:
|
|
2746
|
+
gap: 6px;
|
|
2747
|
+
padding: 6px ${timelineHorizontalPadding}px 8px;
|
|
2124
2748
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2125
2749
|
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 82%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.12)) 18%);
|
|
2750
|
+
contain: content;
|
|
2126
2751
|
}
|
|
2127
2752
|
|
|
2128
2753
|
.ChatDebugViewTimelineTop {
|
|
2129
2754
|
display: flex;
|
|
2130
|
-
align-items:
|
|
2131
|
-
|
|
2132
|
-
gap: 8px;
|
|
2133
|
-
flex-wrap: wrap;
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
.ChatDebugViewTimelineTitle {
|
|
2137
|
-
font-size: 12px;
|
|
2138
|
-
font-weight: 600;
|
|
2755
|
+
align-items: center;
|
|
2756
|
+
contain: content;
|
|
2139
2757
|
}
|
|
2140
2758
|
|
|
2141
2759
|
.ChatDebugViewTimelineSummary {
|
|
2760
|
+
display: flex;
|
|
2761
|
+
align-items: center;
|
|
2142
2762
|
font-size: 12px;
|
|
2763
|
+
line-height: 16px;
|
|
2143
2764
|
opacity: 0.8;
|
|
2765
|
+
contain: content;
|
|
2144
2766
|
}
|
|
2145
2767
|
|
|
2146
2768
|
.ChatDebugViewTimelineControls {
|
|
@@ -2148,61 +2770,93 @@ const getCss = () => {
|
|
|
2148
2770
|
align-items: center;
|
|
2149
2771
|
gap: 8px;
|
|
2150
2772
|
flex-wrap: wrap;
|
|
2773
|
+
contain: content;
|
|
2151
2774
|
}
|
|
2152
2775
|
|
|
2153
|
-
.
|
|
2154
|
-
display:
|
|
2155
|
-
align-items:
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
cursor: pointer;
|
|
2162
|
-
font-size: 12px;
|
|
2776
|
+
.ChatDebugViewTimelineBuckets {
|
|
2777
|
+
display: flex;
|
|
2778
|
+
align-items: end;
|
|
2779
|
+
gap: 3px;
|
|
2780
|
+
flex: 1 1 auto;
|
|
2781
|
+
min-height: 52px;
|
|
2782
|
+
pointer-events: none;
|
|
2783
|
+
contain: strict;
|
|
2163
2784
|
}
|
|
2164
2785
|
|
|
2165
|
-
.
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2786
|
+
.ChatDebugViewTimelineInteractive {
|
|
2787
|
+
display: flex;
|
|
2788
|
+
position: relative;
|
|
2789
|
+
min-height: 52px;
|
|
2790
|
+
cursor: crosshair;
|
|
2791
|
+
user-select: none;
|
|
2792
|
+
contain: strict;
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
.ChatDebugViewTimelineSelectionOverlay {
|
|
2796
|
+
position: absolute;
|
|
2797
|
+
inset: 0;
|
|
2798
|
+
pointer-events: none;
|
|
2799
|
+
contain: strict;
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
.ChatDebugViewTimelineSelectionRange {
|
|
2803
|
+
position: absolute;
|
|
2804
|
+
top: 0;
|
|
2805
|
+
bottom: 0;
|
|
2806
|
+
background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 20%, transparent 80%);
|
|
2807
|
+
border-left: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
|
|
2808
|
+
border-right: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
|
|
2809
|
+
contain: strict;
|
|
2169
2810
|
}
|
|
2170
2811
|
|
|
2171
|
-
.
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2812
|
+
.ChatDebugViewTimelineSelectionMarker {
|
|
2813
|
+
position: absolute;
|
|
2814
|
+
top: 0;
|
|
2815
|
+
bottom: 0;
|
|
2816
|
+
width: 1px;
|
|
2817
|
+
margin-left: -0.5px;
|
|
2818
|
+
background: var(--vscode-focusBorder, #007fd4);
|
|
2819
|
+
box-shadow: 0 0 0 1px color-mix(in srgb, var(--vscode-focusBorder, #007fd4) 24%, transparent 76%);
|
|
2820
|
+
contain: strict;
|
|
2176
2821
|
}
|
|
2177
2822
|
|
|
2178
2823
|
.ChatDebugViewTimelineBucket {
|
|
2824
|
+
--ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 74%, transparent 26%);
|
|
2825
|
+
--ChatDebugViewTimelineBucketBarBorderColor: transparent;
|
|
2179
2826
|
display: flex;
|
|
2180
2827
|
align-items: stretch;
|
|
2181
2828
|
flex: 1 1 10px;
|
|
2182
2829
|
min-width: 10px;
|
|
2183
|
-
min-height:
|
|
2184
|
-
|
|
2830
|
+
min-height: 52px;
|
|
2831
|
+
contain: strict;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
.ChatDebugViewTimelineBucketSelected {
|
|
2835
|
+
--ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
|
|
2836
|
+
--ChatDebugViewTimelineBucketBarBorderColor: var(--vscode-focusBorder, #007fd4);
|
|
2185
2837
|
}
|
|
2186
2838
|
|
|
2187
2839
|
.ChatDebugViewTimelinePresetInput {
|
|
2188
2840
|
position: absolute;
|
|
2189
2841
|
opacity: 0;
|
|
2190
2842
|
pointer-events: none;
|
|
2843
|
+
contain: content;
|
|
2191
2844
|
}
|
|
2192
2845
|
|
|
2193
2846
|
.ChatDebugViewTimelineBucketBar {
|
|
2194
|
-
width: 100%;
|
|
2195
2847
|
display: flex;
|
|
2196
2848
|
flex-direction: column;
|
|
2197
2849
|
justify-content: flex-end;
|
|
2198
2850
|
gap: 2px;
|
|
2199
|
-
padding:
|
|
2851
|
+
padding: 6px 1px 2px;
|
|
2200
2852
|
border: 1px solid transparent;
|
|
2201
|
-
border-radius:
|
|
2202
|
-
|
|
2853
|
+
border-radius: 2px;
|
|
2854
|
+
width: 100%;
|
|
2855
|
+
background: var(--ChatDebugViewTimelineBucketBarBackground);
|
|
2856
|
+
border-color: var(--ChatDebugViewTimelineBucketBarBorderColor);
|
|
2857
|
+
contain: strict;
|
|
2203
2858
|
}
|
|
2204
2859
|
|
|
2205
|
-
.ChatDebugViewTimelineBucketSelected .ChatDebugViewTimelineBucketBar,
|
|
2206
2860
|
.ChatDebugViewTimelineBucketBarSelected {
|
|
2207
2861
|
background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
|
|
2208
2862
|
border-color: var(--vscode-focusBorder, #007fd4);
|
|
@@ -2213,6 +2867,7 @@ const getCss = () => {
|
|
|
2213
2867
|
height: 4px;
|
|
2214
2868
|
border-radius: 999px;
|
|
2215
2869
|
background: var(--vscode-charts-blue, #75beff);
|
|
2870
|
+
contain: strict;
|
|
2216
2871
|
}
|
|
2217
2872
|
|
|
2218
2873
|
.ChatDebugViewTimelineBucketUnitEmpty {
|
|
@@ -2220,30 +2875,41 @@ const getCss = () => {
|
|
|
2220
2875
|
background: var(--vscode-editorWidget-border, #454545);
|
|
2221
2876
|
}
|
|
2222
2877
|
|
|
2223
|
-
.
|
|
2878
|
+
.ChatDebugViewTableHeaderRow,
|
|
2224
2879
|
.ChatDebugViewEventRow {
|
|
2225
2880
|
display: flex;
|
|
2226
2881
|
align-items: center;
|
|
2227
2882
|
gap: 8px;
|
|
2883
|
+
contain: content;
|
|
2228
2884
|
}
|
|
2229
2885
|
|
|
2230
2886
|
.ChatDebugViewTableHeader {
|
|
2231
|
-
padding: 8px;
|
|
2887
|
+
padding: 3px 8px;
|
|
2232
2888
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2233
2889
|
background: var(--vscode-editorWidget-background, transparent);
|
|
2234
2890
|
position: sticky;
|
|
2235
2891
|
top: 0;
|
|
2236
2892
|
z-index: 1;
|
|
2893
|
+
contain: content;
|
|
2237
2894
|
}
|
|
2238
2895
|
|
|
2239
2896
|
.ChatDebugViewHeaderCell {
|
|
2897
|
+
display: flex;
|
|
2898
|
+
align-items: center;
|
|
2899
|
+
overflow: hidden;
|
|
2900
|
+
text-overflow: ellipsis;
|
|
2901
|
+
white-space: nowrap;
|
|
2902
|
+
min-width: 0;
|
|
2240
2903
|
font-size: 11px;
|
|
2241
2904
|
text-transform: uppercase;
|
|
2242
2905
|
letter-spacing: 0.04em;
|
|
2243
2906
|
opacity: 0.8;
|
|
2907
|
+
contain: content;
|
|
2244
2908
|
}
|
|
2245
2909
|
|
|
2246
2910
|
.ChatDebugViewTableBody {
|
|
2911
|
+
display: flex;
|
|
2912
|
+
flex-direction: column;
|
|
2247
2913
|
overflow: auto;
|
|
2248
2914
|
min-height: 0;
|
|
2249
2915
|
flex: 1 1 auto;
|
|
@@ -2252,6 +2918,7 @@ const getCss = () => {
|
|
|
2252
2918
|
|
|
2253
2919
|
.ChatDebugViewEventRowLabel {
|
|
2254
2920
|
display: block;
|
|
2921
|
+
contain: content;
|
|
2255
2922
|
}
|
|
2256
2923
|
|
|
2257
2924
|
.ChatDebugViewEventRowLabelSelected .ChatDebugViewEventRow,
|
|
@@ -2264,23 +2931,28 @@ const getCss = () => {
|
|
|
2264
2931
|
position: absolute;
|
|
2265
2932
|
opacity: 0;
|
|
2266
2933
|
pointer-events: none;
|
|
2934
|
+
contain: content;
|
|
2267
2935
|
}
|
|
2268
2936
|
|
|
2269
2937
|
.ChatDebugViewEventRow {
|
|
2270
|
-
padding: 8px;
|
|
2938
|
+
padding: 2px 8px;
|
|
2271
2939
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2272
2940
|
cursor: pointer;
|
|
2273
2941
|
}
|
|
2274
2942
|
|
|
2275
2943
|
.ChatDebugViewEventRow:hover {
|
|
2276
2944
|
background: var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31));
|
|
2945
|
+
color: var(--vscode-list-hoverForeground, inherit);
|
|
2277
2946
|
}
|
|
2278
2947
|
|
|
2279
2948
|
.ChatDebugViewCell {
|
|
2949
|
+
display: flex;
|
|
2950
|
+
align-items: center;
|
|
2280
2951
|
overflow: hidden;
|
|
2281
2952
|
text-overflow: ellipsis;
|
|
2282
2953
|
white-space: nowrap;
|
|
2283
2954
|
min-width: 0;
|
|
2955
|
+
contain: content;
|
|
2284
2956
|
}
|
|
2285
2957
|
|
|
2286
2958
|
.ChatDebugViewCellType {
|
|
@@ -2295,11 +2967,13 @@ const getCss = () => {
|
|
|
2295
2967
|
|
|
2296
2968
|
.ChatDebugViewCellDuration {
|
|
2297
2969
|
flex: 0 0 90px;
|
|
2970
|
+
justify-content: flex-end;
|
|
2298
2971
|
text-align: right;
|
|
2299
2972
|
}
|
|
2300
2973
|
|
|
2301
2974
|
.ChatDebugViewCellStatus {
|
|
2302
2975
|
flex: 0 0 64px;
|
|
2976
|
+
justify-content: flex-end;
|
|
2303
2977
|
text-align: right;
|
|
2304
2978
|
}
|
|
2305
2979
|
|
|
@@ -2316,25 +2990,31 @@ const getCss = () => {
|
|
|
2316
2990
|
|
|
2317
2991
|
.ChatDebugViewDetailsTop {
|
|
2318
2992
|
display: flex;
|
|
2319
|
-
align-items:
|
|
2320
|
-
justify-content:
|
|
2321
|
-
|
|
2993
|
+
align-items: stretch;
|
|
2994
|
+
justify-content: flex-start;
|
|
2995
|
+
gap: 8px;
|
|
2996
|
+
padding: 0 8px;
|
|
2322
2997
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
.ChatDebugViewDetailsTitle {
|
|
2326
|
-
font-size: 12px;
|
|
2327
|
-
font-weight: 600;
|
|
2998
|
+
contain: content;
|
|
2328
2999
|
}
|
|
2329
3000
|
|
|
2330
3001
|
.ChatDebugViewDetailsClose {
|
|
2331
3002
|
width: 18px;
|
|
2332
3003
|
height: 18px;
|
|
2333
3004
|
appearance: none;
|
|
2334
|
-
border:
|
|
3005
|
+
border: none;
|
|
2335
3006
|
border-radius: 4px;
|
|
2336
3007
|
cursor: pointer;
|
|
2337
3008
|
position: relative;
|
|
3009
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3010
|
+
background: transparent;
|
|
3011
|
+
align-self: center;
|
|
3012
|
+
flex: 0 0 auto;
|
|
3013
|
+
contain: strict;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
.ChatDebugViewDetailsClose:hover {
|
|
3017
|
+
background: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
|
|
2338
3018
|
}
|
|
2339
3019
|
|
|
2340
3020
|
.ChatDebugViewDetailsClose::before,
|
|
@@ -2357,10 +3037,60 @@ const getCss = () => {
|
|
|
2357
3037
|
}
|
|
2358
3038
|
|
|
2359
3039
|
.ChatDebugViewDetailsBody {
|
|
3040
|
+
display: flex;
|
|
3041
|
+
flex-direction: column;
|
|
3042
|
+
overflow: hidden;
|
|
3043
|
+
padding: 0;
|
|
3044
|
+
flex: 1 1 auto;
|
|
3045
|
+
min-height: 0;
|
|
3046
|
+
align-items: stretch;
|
|
3047
|
+
contain: strict;
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
.ChatDebugViewDetailsTabs {
|
|
3051
|
+
display: flex;
|
|
3052
|
+
align-items: center;
|
|
3053
|
+
flex: 1 1 auto;
|
|
3054
|
+
gap: 2px;
|
|
3055
|
+
min-width: 0;
|
|
3056
|
+
padding: 0;
|
|
3057
|
+
overflow-x: auto;
|
|
3058
|
+
contain: content;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
.ChatDebugViewDetailsTab {
|
|
3062
|
+
display: flex;
|
|
3063
|
+
align-items: center;
|
|
3064
|
+
justify-content: center;
|
|
3065
|
+
min-height: 32px;
|
|
3066
|
+
padding: 0 10px;
|
|
3067
|
+
appearance: none;
|
|
3068
|
+
background: transparent;
|
|
3069
|
+
border: 0;
|
|
3070
|
+
border-bottom: 2px solid transparent;
|
|
3071
|
+
color: var(--vscode-descriptionForeground, var(--vscode-foreground, #cccccc));
|
|
3072
|
+
cursor: pointer;
|
|
3073
|
+
white-space: nowrap;
|
|
3074
|
+
contain: strict;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
.ChatDebugViewDetailsTab:hover {
|
|
3078
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
.ChatDebugViewDetailsTabSelected {
|
|
3082
|
+
border-bottom-color: var(--vscode-focusBorder, #007fd4);
|
|
3083
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
.ChatDebugViewDetailsPanel {
|
|
3087
|
+
display: flex;
|
|
3088
|
+
flex-direction: column;
|
|
2360
3089
|
overflow: auto;
|
|
2361
3090
|
padding: 8px;
|
|
2362
3091
|
flex: 1 1 auto;
|
|
2363
3092
|
min-height: 0;
|
|
3093
|
+
align-items: flex-start;
|
|
2364
3094
|
contain: strict;
|
|
2365
3095
|
}
|
|
2366
3096
|
|
|
@@ -2389,25 +3119,101 @@ const getCss = () => {
|
|
|
2389
3119
|
}
|
|
2390
3120
|
|
|
2391
3121
|
.ChatDebugViewEvent {
|
|
3122
|
+
display: flex;
|
|
3123
|
+
flex-direction: column;
|
|
3124
|
+
width: max-content;
|
|
3125
|
+
min-width: 100%;
|
|
2392
3126
|
margin: 0;
|
|
2393
3127
|
padding: 8px;
|
|
2394
3128
|
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2395
3129
|
border-radius: 6px;
|
|
2396
3130
|
margin-bottom: 8px;
|
|
2397
|
-
white-space:
|
|
2398
|
-
word-break: break-word;
|
|
3131
|
+
white-space: nowrap;
|
|
2399
3132
|
font-family: var(--vscode-editor-font-family, monospace);
|
|
2400
3133
|
font-size: 12px;
|
|
2401
3134
|
user-select: text;
|
|
3135
|
+
contain: content;
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
.row {
|
|
3139
|
+
display: flex;
|
|
3140
|
+
align-items: baseline;
|
|
3141
|
+
min-width: 100%;
|
|
3142
|
+
width: max-content;
|
|
3143
|
+
white-space: nowrap;
|
|
3144
|
+
contain: content;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
.ChatDebugViewEventLineNumber {
|
|
3148
|
+
display: flex;
|
|
3149
|
+
justify-content: flex-end;
|
|
3150
|
+
flex: 0 0 3ch;
|
|
3151
|
+
margin-right: 12px;
|
|
3152
|
+
opacity: 0.6;
|
|
3153
|
+
user-select: none;
|
|
3154
|
+
contain: content;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
.ChatDebugViewEventLineContent {
|
|
3158
|
+
display: flex;
|
|
3159
|
+
white-space: pre;
|
|
3160
|
+
contain: content;
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
.ChatDebugViewDetailsPanel > .ChatDebugViewEvent {
|
|
3164
|
+
border: 0;
|
|
3165
|
+
border-radius: 0;
|
|
3166
|
+
margin-bottom: 0;
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
.ChatDebugViewTiming {
|
|
3170
|
+
display: flex;
|
|
3171
|
+
flex-direction: column;
|
|
3172
|
+
width: 100%;
|
|
3173
|
+
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
3174
|
+
border-radius: 6px;
|
|
3175
|
+
overflow: hidden;
|
|
3176
|
+
contain: strict;
|
|
3177
|
+
flex: 1;
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
.ChatDebugViewTimingRow {
|
|
3181
|
+
display: flex;
|
|
3182
|
+
align-items: center;
|
|
3183
|
+
justify-content: space-between;
|
|
3184
|
+
gap: 12px;
|
|
3185
|
+
padding: 8px 10px;
|
|
3186
|
+
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
3187
|
+
contain: content;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
.ChatDebugViewTimingRow:last-child {
|
|
3191
|
+
border-bottom: 0;
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
.ChatDebugViewTimingLabel {
|
|
3195
|
+
opacity: 0.8;
|
|
3196
|
+
contain: content;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
.ChatDebugViewTimingValue {
|
|
3200
|
+
text-align: right;
|
|
3201
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
3202
|
+
contain: content;
|
|
2402
3203
|
}
|
|
2403
3204
|
|
|
2404
3205
|
.ChatDebugViewEmpty {
|
|
3206
|
+
display: flex;
|
|
3207
|
+
align-items: center;
|
|
2405
3208
|
opacity: 0.8;
|
|
3209
|
+
contain: content;
|
|
2406
3210
|
}
|
|
2407
3211
|
|
|
2408
3212
|
.ChatDebugViewError {
|
|
3213
|
+
display: flex;
|
|
2409
3214
|
color: var(--vscode-errorForeground, #f14c4c);
|
|
2410
3215
|
white-space: normal;
|
|
3216
|
+
contain: content;
|
|
2411
3217
|
}
|
|
2412
3218
|
|
|
2413
3219
|
.TokenText {
|
|
@@ -2431,33 +3237,48 @@ const getCss = () => {
|
|
|
2431
3237
|
}
|
|
2432
3238
|
|
|
2433
3239
|
.ChatOrderedList{
|
|
3240
|
+
display:flex;
|
|
3241
|
+
flex-direction:column;
|
|
2434
3242
|
margin:0;
|
|
2435
3243
|
padding:0;
|
|
2436
3244
|
padding-left:10px;
|
|
3245
|
+
contain: content;
|
|
2437
3246
|
}
|
|
2438
3247
|
|
|
2439
3248
|
.ChatOrderedListItem{
|
|
3249
|
+
display:flex;
|
|
2440
3250
|
margin:0;
|
|
2441
3251
|
padding:0;
|
|
3252
|
+
contain: content;
|
|
2442
3253
|
}
|
|
2443
3254
|
|
|
2444
3255
|
.ChatToolCalls{
|
|
3256
|
+
display:flex;
|
|
3257
|
+
flex-direction:column;
|
|
2445
3258
|
margin:0;
|
|
2446
3259
|
padding:0;
|
|
3260
|
+
contain: content;
|
|
2447
3261
|
}
|
|
2448
3262
|
`;
|
|
2449
3263
|
};
|
|
2450
3264
|
|
|
2451
3265
|
const renderCss = (oldState, newState) => {
|
|
2452
|
-
const css = getCss();
|
|
3266
|
+
const css = getCss(newState);
|
|
2453
3267
|
return [SetCss, newState.uid, css];
|
|
2454
3268
|
};
|
|
2455
3269
|
|
|
3270
|
+
const Button = 1;
|
|
2456
3271
|
const Div = 4;
|
|
2457
3272
|
const Input = 6;
|
|
2458
3273
|
const Span = 8;
|
|
3274
|
+
const Table = 9;
|
|
3275
|
+
const TBody = 10;
|
|
3276
|
+
const Td = 11;
|
|
2459
3277
|
const Text = 12;
|
|
2460
|
-
const
|
|
3278
|
+
const Th = 13;
|
|
3279
|
+
const THead = 14;
|
|
3280
|
+
const Tr = 15;
|
|
3281
|
+
const Search = 42;
|
|
2461
3282
|
const Label = 66;
|
|
2462
3283
|
const Reference = 100;
|
|
2463
3284
|
|
|
@@ -2757,10 +3578,65 @@ const diffTree = (oldNodes, newNodes) => {
|
|
|
2757
3578
|
return removeTrailingNavigationPatches(patches);
|
|
2758
3579
|
};
|
|
2759
3580
|
|
|
3581
|
+
const getDebugErrorDom = errorMessage => {
|
|
3582
|
+
return [{
|
|
3583
|
+
childCount: 1,
|
|
3584
|
+
className: 'ChatDebugView',
|
|
3585
|
+
type: Div
|
|
3586
|
+
}, {
|
|
3587
|
+
childCount: 1,
|
|
3588
|
+
className: 'ChatDebugViewError',
|
|
3589
|
+
type: Div
|
|
3590
|
+
}, text(errorMessage)];
|
|
3591
|
+
};
|
|
3592
|
+
|
|
2760
3593
|
const HandleInput = 4;
|
|
2761
3594
|
const HandleFilterInput = 5;
|
|
2762
3595
|
const HandleSimpleInput = 6;
|
|
2763
3596
|
const HandleEventRowClick = 7;
|
|
3597
|
+
const HandleSashPointerDown = 8;
|
|
3598
|
+
const HandleSashPointerMove = 9;
|
|
3599
|
+
const HandleSashPointerUp = 10;
|
|
3600
|
+
const HandleTableBodyContextMenu = 11;
|
|
3601
|
+
const HandleTimelinePointerDown = 12;
|
|
3602
|
+
const HandleTimelinePointerMove = 13;
|
|
3603
|
+
const HandleTimelinePointerUp = 14;
|
|
3604
|
+
const HandleTimelineDoubleClick = 15;
|
|
3605
|
+
|
|
3606
|
+
const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
|
|
3607
|
+
if (useDevtoolsLayout) {
|
|
3608
|
+
return [{
|
|
3609
|
+
childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
|
|
3610
|
+
className: 'ChatDebugViewTop ChatDebugViewTop--devtools',
|
|
3611
|
+
type: Search
|
|
3612
|
+
}, {
|
|
3613
|
+
autocomplete: 'off',
|
|
3614
|
+
childCount: 0,
|
|
3615
|
+
className: 'InputBox ChatDebugViewFilterInput ChatDebugViewFilterInput--devtools',
|
|
3616
|
+
inputType: 'search',
|
|
3617
|
+
name: Filter,
|
|
3618
|
+
onInput: HandleFilterInput,
|
|
3619
|
+
placeholder: 'Filter events',
|
|
3620
|
+
type: Input,
|
|
3621
|
+
value: filterValue
|
|
3622
|
+
}, ...quickFilterNodes];
|
|
3623
|
+
}
|
|
3624
|
+
return [{
|
|
3625
|
+
childCount: 1,
|
|
3626
|
+
className: 'ChatDebugViewTop',
|
|
3627
|
+
type: Search
|
|
3628
|
+
}, {
|
|
3629
|
+
autocomplete: 'off',
|
|
3630
|
+
childCount: 0,
|
|
3631
|
+
className: 'InputBox ChatDebugViewFilterInput',
|
|
3632
|
+
inputType: 'search',
|
|
3633
|
+
name: Filter,
|
|
3634
|
+
onInput: HandleFilterInput,
|
|
3635
|
+
placeholder: 'Filter events',
|
|
3636
|
+
type: Input,
|
|
3637
|
+
value: filterValue
|
|
3638
|
+
}];
|
|
3639
|
+
};
|
|
2764
3640
|
|
|
2765
3641
|
const getDurationText = event => {
|
|
2766
3642
|
const explicitDuration = event.durationMs ?? event.duration;
|
|
@@ -2812,6 +3688,129 @@ const getStartText = event => {
|
|
|
2812
3688
|
return getTimestampText(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
2813
3689
|
};
|
|
2814
3690
|
|
|
3691
|
+
const getTimingRowDom = (label, value) => {
|
|
3692
|
+
return [{
|
|
3693
|
+
childCount: 2,
|
|
3694
|
+
className: 'ChatDebugViewTimingRow',
|
|
3695
|
+
type: Div
|
|
3696
|
+
}, {
|
|
3697
|
+
childCount: 1,
|
|
3698
|
+
className: 'ChatDebugViewTimingLabel',
|
|
3699
|
+
type: Span
|
|
3700
|
+
}, text(label), {
|
|
3701
|
+
childCount: 1,
|
|
3702
|
+
className: 'ChatDebugViewTimingValue',
|
|
3703
|
+
type: Span
|
|
3704
|
+
}, text(value)];
|
|
3705
|
+
};
|
|
3706
|
+
const getTimingDetailsDom = event => {
|
|
3707
|
+
return [{
|
|
3708
|
+
childCount: 3,
|
|
3709
|
+
className: 'ChatDebugViewTiming',
|
|
3710
|
+
type: Div
|
|
3711
|
+
}, ...getTimingRowDom('Started', getStartText(event)), ...getTimingRowDom('Ended', getEndText(event)), ...getTimingRowDom('Duration', getDurationText(event))];
|
|
3712
|
+
};
|
|
3713
|
+
|
|
3714
|
+
const getTabId = detailTab => {
|
|
3715
|
+
return `ChatDebugViewDetailsTab-${detailTab}`;
|
|
3716
|
+
};
|
|
3717
|
+
const getPanelId = detailTab => {
|
|
3718
|
+
return `ChatDebugViewDetailsPanel-${detailTab}`;
|
|
3719
|
+
};
|
|
3720
|
+
const getTabNodes = selectedDetailTab => {
|
|
3721
|
+
return detailTabs.flatMap(detailTab => {
|
|
3722
|
+
const isSelected = detailTab === selectedDetailTab;
|
|
3723
|
+
return [{
|
|
3724
|
+
'aria-controls': getPanelId(detailTab),
|
|
3725
|
+
'aria-selected': isSelected,
|
|
3726
|
+
childCount: 1,
|
|
3727
|
+
className: isSelected ? 'ChatDebugViewDetailsTab ChatDebugViewDetailsTabSelected' : 'ChatDebugViewDetailsTab',
|
|
3728
|
+
id: getTabId(detailTab),
|
|
3729
|
+
name: DetailTab,
|
|
3730
|
+
onChange: HandleSimpleInput,
|
|
3731
|
+
onClick: HandleSimpleInput,
|
|
3732
|
+
role: 'tab',
|
|
3733
|
+
tabIndex: isSelected ? 0 : -1,
|
|
3734
|
+
type: Button,
|
|
3735
|
+
value: detailTab
|
|
3736
|
+
}, text(getDetailTabLabel(detailTab))];
|
|
3737
|
+
});
|
|
3738
|
+
};
|
|
3739
|
+
const getDetailsDom = (selectedEventNodes, selectedEvent = null, selectedDetailTab = Response) => {
|
|
3740
|
+
if (selectedEventNodes.length === 0) {
|
|
3741
|
+
return [];
|
|
3742
|
+
}
|
|
3743
|
+
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) : selectedEventNodes;
|
|
3744
|
+
return [{
|
|
3745
|
+
childCount: 2,
|
|
3746
|
+
className: 'ChatDebugViewDetails',
|
|
3747
|
+
type: Div
|
|
3748
|
+
}, {
|
|
3749
|
+
childCount: 2,
|
|
3750
|
+
className: 'ChatDebugViewDetailsTop',
|
|
3751
|
+
type: Div
|
|
3752
|
+
}, {
|
|
3753
|
+
'aria-label': 'Detail sections',
|
|
3754
|
+
childCount: detailTabs.length,
|
|
3755
|
+
className: 'ChatDebugViewDetailsTabs',
|
|
3756
|
+
role: 'tablist',
|
|
3757
|
+
type: Div
|
|
3758
|
+
}, ...getTabNodes(selectedDetailTab), {
|
|
3759
|
+
'aria-label': 'Close details',
|
|
3760
|
+
childCount: 0,
|
|
3761
|
+
className: 'ChatDebugViewDetailsClose',
|
|
3762
|
+
name: CloseDetails,
|
|
3763
|
+
onChange: HandleSimpleInput,
|
|
3764
|
+
onClick: HandleSimpleInput,
|
|
3765
|
+
type: Button,
|
|
3766
|
+
value: 'close'
|
|
3767
|
+
}, {
|
|
3768
|
+
childCount: 1,
|
|
3769
|
+
className: 'ChatDebugViewDetailsBody',
|
|
3770
|
+
type: Div
|
|
3771
|
+
}, {
|
|
3772
|
+
'aria-labelledby': getTabId(selectedDetailTab),
|
|
3773
|
+
childCount: 1,
|
|
3774
|
+
className: 'ChatDebugViewDetailsPanel',
|
|
3775
|
+
id: getPanelId(selectedDetailTab),
|
|
3776
|
+
role: 'tabpanel',
|
|
3777
|
+
type: Div
|
|
3778
|
+
}, ...contentNodes];
|
|
3779
|
+
};
|
|
3780
|
+
|
|
3781
|
+
const toolExecutionTypePrefix = 'tool-execution';
|
|
3782
|
+
const getToolName = event => {
|
|
3783
|
+
if (typeof event.toolName === 'string' && event.toolName) {
|
|
3784
|
+
return event.toolName;
|
|
3785
|
+
}
|
|
3786
|
+
if (typeof event.name === 'string' && event.name) {
|
|
3787
|
+
return event.name;
|
|
3788
|
+
}
|
|
3789
|
+
const {
|
|
3790
|
+
arguments: toolArguments
|
|
3791
|
+
} = event;
|
|
3792
|
+
if (!toolArguments || typeof toolArguments !== 'object') {
|
|
3793
|
+
return undefined;
|
|
3794
|
+
}
|
|
3795
|
+
const {
|
|
3796
|
+
name
|
|
3797
|
+
} = toolArguments;
|
|
3798
|
+
if (typeof name !== 'string' || !name) {
|
|
3799
|
+
return undefined;
|
|
3800
|
+
}
|
|
3801
|
+
return name;
|
|
3802
|
+
};
|
|
3803
|
+
const getEventTypeLabel = event => {
|
|
3804
|
+
if (!event.type.startsWith(toolExecutionTypePrefix)) {
|
|
3805
|
+
return event.type;
|
|
3806
|
+
}
|
|
3807
|
+
const toolName = getToolName(event);
|
|
3808
|
+
if (!toolName) {
|
|
3809
|
+
return event.type;
|
|
3810
|
+
}
|
|
3811
|
+
return `${event.type}, ${toolName}`;
|
|
3812
|
+
};
|
|
3813
|
+
|
|
2815
3814
|
const hasErrorStatus = event => {
|
|
2816
3815
|
if (event.type === 'error') {
|
|
2817
3816
|
return true;
|
|
@@ -2839,75 +3838,63 @@ const getStatusText = event => {
|
|
|
2839
3838
|
};
|
|
2840
3839
|
|
|
2841
3840
|
const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
2842
|
-
|
|
2843
|
-
return [{
|
|
2844
|
-
childCount: 1,
|
|
2845
|
-
className: 'ChatDebugViewEmpty',
|
|
2846
|
-
type: Div
|
|
2847
|
-
}, text('No events')];
|
|
2848
|
-
}
|
|
2849
|
-
const rows = [];
|
|
2850
|
-
for (let i = 0; i < events.length; i++) {
|
|
2851
|
-
const event = events[i];
|
|
3841
|
+
return events.flatMap((event, i) => {
|
|
2852
3842
|
const isSelected = selectedEventIndex === i;
|
|
2853
3843
|
const rowIndex = String(i);
|
|
2854
|
-
|
|
2855
|
-
childCount:
|
|
3844
|
+
return [{
|
|
3845
|
+
childCount: 3,
|
|
2856
3846
|
className: `ChatDebugViewEventRow${isSelected ? ' ChatDebugViewEventRowSelected' : ''}`,
|
|
2857
3847
|
'data-index': rowIndex,
|
|
2858
|
-
type:
|
|
3848
|
+
type: Tr
|
|
2859
3849
|
}, {
|
|
2860
3850
|
childCount: 1,
|
|
2861
3851
|
className: 'ChatDebugViewCell ChatDebugViewCellType',
|
|
2862
3852
|
'data-index': rowIndex,
|
|
2863
|
-
type:
|
|
2864
|
-
}, text(event
|
|
2865
|
-
childCount: 1,
|
|
2866
|
-
className: 'ChatDebugViewCell ChatDebugViewCellTime',
|
|
2867
|
-
'data-index': rowIndex,
|
|
2868
|
-
type: Div
|
|
2869
|
-
}, text(getStartText(event)), {
|
|
2870
|
-
childCount: 1,
|
|
2871
|
-
className: 'ChatDebugViewCell ChatDebugViewCellTime',
|
|
2872
|
-
'data-index': rowIndex,
|
|
2873
|
-
type: Div
|
|
2874
|
-
}, text(getEndText(event)), {
|
|
3853
|
+
type: Td
|
|
3854
|
+
}, text(getEventTypeLabel(event)), {
|
|
2875
3855
|
childCount: 1,
|
|
2876
3856
|
className: 'ChatDebugViewCell ChatDebugViewCellDuration',
|
|
2877
3857
|
'data-index': rowIndex,
|
|
2878
|
-
type:
|
|
3858
|
+
type: Td
|
|
2879
3859
|
}, text(getDurationText(event)), {
|
|
2880
3860
|
childCount: 1,
|
|
2881
3861
|
className: 'ChatDebugViewCell ChatDebugViewCellStatus',
|
|
2882
3862
|
'data-index': rowIndex,
|
|
2883
|
-
type:
|
|
2884
|
-
}, text(getStatusText(event))
|
|
3863
|
+
type: Td
|
|
3864
|
+
}, text(getStatusText(event))];
|
|
3865
|
+
});
|
|
3866
|
+
};
|
|
3867
|
+
|
|
3868
|
+
const getEmptyStateDom = emptyMessage => {
|
|
3869
|
+
return [{
|
|
3870
|
+
childCount: 1,
|
|
3871
|
+
className: 'ChatDebugViewEmpty',
|
|
3872
|
+
type: Div
|
|
3873
|
+
}, text(emptyMessage)];
|
|
3874
|
+
};
|
|
3875
|
+
|
|
3876
|
+
const pushToken = (segments, className, value) => {
|
|
3877
|
+
if (!value) {
|
|
3878
|
+
return segments;
|
|
3879
|
+
}
|
|
3880
|
+
const lastSegment = segments.at(-1);
|
|
3881
|
+
if (lastSegment && lastSegment.className === className) {
|
|
3882
|
+
const merged = {
|
|
3883
|
+
className,
|
|
3884
|
+
value: lastSegment.value + value
|
|
3885
|
+
};
|
|
3886
|
+
return [...segments.slice(0, -1), merged];
|
|
2885
3887
|
}
|
|
2886
|
-
return
|
|
3888
|
+
return [...segments, {
|
|
3889
|
+
className,
|
|
3890
|
+
value
|
|
3891
|
+
}];
|
|
2887
3892
|
};
|
|
2888
3893
|
|
|
2889
3894
|
const numberRegex = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
|
|
2890
3895
|
const whitespaceRegex = /\s/u;
|
|
2891
3896
|
const getTokenSegments = json => {
|
|
2892
|
-
|
|
2893
|
-
const pushToken = (className, value) => {
|
|
2894
|
-
if (!value) {
|
|
2895
|
-
return;
|
|
2896
|
-
}
|
|
2897
|
-
const lastSegment = segments.at(-1);
|
|
2898
|
-
if (lastSegment && lastSegment.className === className) {
|
|
2899
|
-
const merged = {
|
|
2900
|
-
className,
|
|
2901
|
-
value: lastSegment.value + value
|
|
2902
|
-
};
|
|
2903
|
-
segments[segments.length - 1] = merged;
|
|
2904
|
-
return;
|
|
2905
|
-
}
|
|
2906
|
-
segments.push({
|
|
2907
|
-
className,
|
|
2908
|
-
value
|
|
2909
|
-
});
|
|
2910
|
-
};
|
|
3897
|
+
let segments = [];
|
|
2911
3898
|
let i = 0;
|
|
2912
3899
|
while (i < json.length) {
|
|
2913
3900
|
const character = json[i];
|
|
@@ -2932,46 +3919,68 @@ const getTokenSegments = json => {
|
|
|
2932
3919
|
lookAheadIndex++;
|
|
2933
3920
|
}
|
|
2934
3921
|
const className = json[lookAheadIndex] === ':' ? 'TokenKey' : 'TokenString';
|
|
2935
|
-
pushToken(className, tokenValue);
|
|
3922
|
+
segments = pushToken(segments, className, tokenValue);
|
|
2936
3923
|
continue;
|
|
2937
3924
|
}
|
|
2938
3925
|
const numberMatch = numberRegex.exec(json.slice(i));
|
|
2939
3926
|
if (numberMatch) {
|
|
2940
|
-
pushToken('TokenNumeric', numberMatch[0]);
|
|
3927
|
+
segments = pushToken(segments, 'TokenNumeric', numberMatch[0]);
|
|
2941
3928
|
i += numberMatch[0].length;
|
|
2942
3929
|
continue;
|
|
2943
3930
|
}
|
|
2944
3931
|
if (json.startsWith('true', i)) {
|
|
2945
|
-
pushToken('TokenBoolean', 'true');
|
|
3932
|
+
segments = pushToken(segments, 'TokenBoolean', 'true');
|
|
2946
3933
|
i += 4;
|
|
2947
3934
|
continue;
|
|
2948
3935
|
}
|
|
2949
3936
|
if (json.startsWith('false', i)) {
|
|
2950
|
-
pushToken('TokenBoolean', 'false');
|
|
3937
|
+
segments = pushToken(segments, 'TokenBoolean', 'false');
|
|
2951
3938
|
i += 5;
|
|
2952
3939
|
continue;
|
|
2953
3940
|
}
|
|
2954
3941
|
if (json.startsWith('null', i)) {
|
|
2955
|
-
pushToken('TokenBoolean', 'null');
|
|
3942
|
+
segments = pushToken(segments, 'TokenBoolean', 'null');
|
|
2956
3943
|
i += 4;
|
|
2957
3944
|
continue;
|
|
2958
3945
|
}
|
|
2959
|
-
pushToken('TokenText', character);
|
|
3946
|
+
segments = pushToken(segments, 'TokenText', character);
|
|
2960
3947
|
i++;
|
|
2961
3948
|
}
|
|
2962
3949
|
return segments;
|
|
2963
3950
|
};
|
|
2964
|
-
|
|
3951
|
+
|
|
3952
|
+
const getJsonLines = value => {
|
|
2965
3953
|
const json = JSON.stringify(value, null, 2);
|
|
2966
3954
|
if (!json) {
|
|
2967
|
-
return [{
|
|
2968
|
-
childCount: 1,
|
|
3955
|
+
return [[{
|
|
2969
3956
|
className: 'TokenText',
|
|
2970
|
-
|
|
2971
|
-
}
|
|
3957
|
+
value: String(json)
|
|
3958
|
+
}]];
|
|
3959
|
+
}
|
|
3960
|
+
const segments = getTokenSegments(json);
|
|
3961
|
+
const lines = [];
|
|
3962
|
+
let currentLine = [];
|
|
3963
|
+
for (const segment of segments) {
|
|
3964
|
+
const parts = segment.value.split('\n');
|
|
3965
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3966
|
+
const part = parts[i];
|
|
3967
|
+
if (part) {
|
|
3968
|
+
currentLine.push({
|
|
3969
|
+
className: segment.className,
|
|
3970
|
+
value: part
|
|
3971
|
+
});
|
|
3972
|
+
}
|
|
3973
|
+
if (i < parts.length - 1) {
|
|
3974
|
+
lines.push(currentLine);
|
|
3975
|
+
currentLine = [];
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
2972
3978
|
}
|
|
2973
|
-
|
|
2974
|
-
return
|
|
3979
|
+
lines.push(currentLine);
|
|
3980
|
+
return lines;
|
|
3981
|
+
};
|
|
3982
|
+
const getLineContentNodes = line => {
|
|
3983
|
+
return line.flatMap(segment => {
|
|
2975
3984
|
return [{
|
|
2976
3985
|
childCount: 1,
|
|
2977
3986
|
className: segment.className,
|
|
@@ -2979,20 +3988,141 @@ const getJsonTokenNodes = value => {
|
|
|
2979
3988
|
}, text(segment.value)];
|
|
2980
3989
|
});
|
|
2981
3990
|
};
|
|
2982
|
-
|
|
3991
|
+
const getLineNodes = lines => {
|
|
3992
|
+
return lines.flatMap((line, index) => {
|
|
3993
|
+
const lineContentNodes = getLineContentNodes(line);
|
|
3994
|
+
return [{
|
|
3995
|
+
childCount: 2,
|
|
3996
|
+
className: 'row',
|
|
3997
|
+
type: Div
|
|
3998
|
+
}, {
|
|
3999
|
+
childCount: 1,
|
|
4000
|
+
className: 'ChatDebugViewEventLineNumber',
|
|
4001
|
+
type: Span
|
|
4002
|
+
}, text(String(index + 1)), {
|
|
4003
|
+
childCount: lineContentNodes.length / 2,
|
|
4004
|
+
className: 'ChatDebugViewEventLineContent',
|
|
4005
|
+
type: Span
|
|
4006
|
+
}, ...lineContentNodes];
|
|
4007
|
+
});
|
|
4008
|
+
};
|
|
2983
4009
|
const getEventNode = event => {
|
|
2984
|
-
const
|
|
4010
|
+
const renderedEvent = {
|
|
4011
|
+
...event,
|
|
4012
|
+
type: getEventTypeLabel(event)
|
|
4013
|
+
};
|
|
4014
|
+
const lines = getJsonLines(renderedEvent);
|
|
4015
|
+
const lineNodes = getLineNodes(lines);
|
|
2985
4016
|
return [{
|
|
2986
|
-
childCount:
|
|
4017
|
+
childCount: lines.length,
|
|
2987
4018
|
className: 'ChatDebugViewEvent',
|
|
2988
|
-
type:
|
|
2989
|
-
}, ...
|
|
4019
|
+
type: Div
|
|
4020
|
+
}, ...lineNodes];
|
|
2990
4021
|
};
|
|
2991
4022
|
|
|
2992
|
-
const
|
|
2993
|
-
const
|
|
2994
|
-
|
|
2995
|
-
|
|
4023
|
+
const getEventsClassName = hasSelectedEvent => {
|
|
4024
|
+
const widthClassName = hasSelectedEvent ? 'ChatDebugViewEvents' : 'ChatDebugViewEvents ChatDebugViewEventsFullWidth';
|
|
4025
|
+
return widthClassName;
|
|
4026
|
+
};
|
|
4027
|
+
|
|
4028
|
+
const getSashNodesDom = hasSelectedEvent => {
|
|
4029
|
+
if (!hasSelectedEvent) {
|
|
4030
|
+
return [];
|
|
4031
|
+
}
|
|
4032
|
+
return [{
|
|
4033
|
+
childCount: 1,
|
|
4034
|
+
className: 'ChatDebugViewSash',
|
|
4035
|
+
onPointerDown: HandleSashPointerDown,
|
|
4036
|
+
type: Div
|
|
4037
|
+
}, {
|
|
4038
|
+
childCount: 0,
|
|
4039
|
+
className: 'ChatDebugViewSashLine',
|
|
4040
|
+
type: Div
|
|
4041
|
+
}];
|
|
4042
|
+
};
|
|
4043
|
+
|
|
4044
|
+
const getTableBodyDom = (rowNodes, eventCount) => {
|
|
4045
|
+
return [{
|
|
4046
|
+
childCount: eventCount === 0 ? 1 : eventCount,
|
|
4047
|
+
className: 'ChatDebugViewTableBody',
|
|
4048
|
+
onContextMenu: HandleTableBodyContextMenu,
|
|
4049
|
+
onPointerDown: HandleEventRowClick,
|
|
4050
|
+
type: TBody
|
|
4051
|
+
}, ...rowNodes];
|
|
4052
|
+
};
|
|
4053
|
+
|
|
4054
|
+
const getTableHeaderDom = () => {
|
|
4055
|
+
return [{
|
|
4056
|
+
childCount: 1,
|
|
4057
|
+
className: 'ChatDebugViewTableHeader',
|
|
4058
|
+
type: THead
|
|
4059
|
+
}, {
|
|
4060
|
+
childCount: 3,
|
|
4061
|
+
className: 'ChatDebugViewTableHeaderRow',
|
|
4062
|
+
type: Tr
|
|
4063
|
+
}, {
|
|
4064
|
+
childCount: 1,
|
|
4065
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellType',
|
|
4066
|
+
scope: 'col',
|
|
4067
|
+
type: Th
|
|
4068
|
+
}, text('Type'), {
|
|
4069
|
+
childCount: 1,
|
|
4070
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellDuration',
|
|
4071
|
+
scope: 'col',
|
|
4072
|
+
type: Th
|
|
4073
|
+
}, text('Duration'), {
|
|
4074
|
+
childCount: 1,
|
|
4075
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellStatus',
|
|
4076
|
+
scope: 'col',
|
|
4077
|
+
type: Th
|
|
4078
|
+
}, text('Status')];
|
|
4079
|
+
};
|
|
4080
|
+
|
|
4081
|
+
const getTableDom = (rowNodes, eventCount) => {
|
|
4082
|
+
return [{
|
|
4083
|
+
childCount: 2,
|
|
4084
|
+
className: 'ChatDebugViewTable',
|
|
4085
|
+
type: Table
|
|
4086
|
+
}, ...getTableHeaderDom(), ...getTableBodyDom(rowNodes, eventCount)];
|
|
4087
|
+
};
|
|
4088
|
+
|
|
4089
|
+
const getBucketUnitDom = unitCount => {
|
|
4090
|
+
if (unitCount === 0) {
|
|
4091
|
+
return [{
|
|
4092
|
+
childCount: 0,
|
|
4093
|
+
className: 'ChatDebugViewTimelineBucketUnit ChatDebugViewTimelineBucketUnitEmpty',
|
|
4094
|
+
type: Div
|
|
4095
|
+
}];
|
|
4096
|
+
}
|
|
4097
|
+
return Array.from({
|
|
4098
|
+
length: unitCount
|
|
4099
|
+
}).fill({
|
|
4100
|
+
childCount: 0,
|
|
4101
|
+
className: 'ChatDebugViewTimelineBucketUnit',
|
|
4102
|
+
type: Div
|
|
4103
|
+
});
|
|
4104
|
+
};
|
|
4105
|
+
|
|
4106
|
+
const getBucketDom = bucket => {
|
|
4107
|
+
const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
|
|
4108
|
+
return [{
|
|
4109
|
+
childCount: 2,
|
|
4110
|
+
className: `ChatDebugViewTimelineBucket${bucket.isSelected ? ' ChatDebugViewTimelineBucketSelected' : ''}`,
|
|
4111
|
+
type: Label
|
|
4112
|
+
}, {
|
|
4113
|
+
checked: false,
|
|
4114
|
+
childCount: 0,
|
|
4115
|
+
className: 'ChatDebugViewTimelinePresetInput',
|
|
4116
|
+
inputType: 'radio',
|
|
4117
|
+
name: TimelineRangePreset,
|
|
4118
|
+
onChange: HandleSimpleInput,
|
|
4119
|
+
type: Input,
|
|
4120
|
+
value: presetValue
|
|
4121
|
+
}, {
|
|
4122
|
+
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
4123
|
+
className: `ChatDebugViewTimelineBucketBar${bucket.isSelected ? ' ChatDebugViewTimelineBucketBarSelected' : ''}`,
|
|
4124
|
+
type: Div
|
|
4125
|
+
}, ...getBucketUnitDom(bucket.unitCount)];
|
|
2996
4126
|
};
|
|
2997
4127
|
|
|
2998
4128
|
const formatTimelineSeconds = value => {
|
|
@@ -3001,6 +4131,7 @@ const formatTimelineSeconds = value => {
|
|
|
3001
4131
|
}
|
|
3002
4132
|
return `${Number(value.toFixed(1))}s`;
|
|
3003
4133
|
};
|
|
4134
|
+
|
|
3004
4135
|
const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSeconds) => {
|
|
3005
4136
|
const timelineInfo = getTimelineInfo(timelineEvents, timelineStartSeconds, timelineEndSeconds);
|
|
3006
4137
|
if (timelineInfo.hasSelection && timelineInfo.startSeconds !== null && timelineInfo.endSeconds !== null) {
|
|
@@ -3009,156 +4140,96 @@ const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSec
|
|
|
3009
4140
|
return `Window 0s-${formatTimelineSeconds(timelineInfo.durationSeconds)} of ${formatTimelineSeconds(timelineInfo.durationSeconds)}`;
|
|
3010
4141
|
};
|
|
3011
4142
|
|
|
3012
|
-
const
|
|
3013
|
-
|
|
4143
|
+
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4144
|
+
if (!timelineSelectionActive) {
|
|
4145
|
+
return {
|
|
4146
|
+
endSeconds: timelineEndSeconds,
|
|
4147
|
+
startSeconds: timelineStartSeconds
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
return {
|
|
4151
|
+
endSeconds: timelineSelectionFocusSeconds,
|
|
4152
|
+
startSeconds: timelineSelectionAnchorSeconds
|
|
4153
|
+
};
|
|
4154
|
+
};
|
|
4155
|
+
const formatPercent = value => {
|
|
4156
|
+
return `${Number(value.toFixed(3))}%`;
|
|
4157
|
+
};
|
|
4158
|
+
const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '') => {
|
|
4159
|
+
const effectiveRange = getEffectiveTimelineRange(timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4160
|
+
const timelineInfo = getTimelineInfo(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds);
|
|
3014
4161
|
if (timelineInfo.buckets.length === 0) {
|
|
3015
4162
|
return [];
|
|
3016
4163
|
}
|
|
3017
|
-
|
|
3018
|
-
childCount:
|
|
3019
|
-
className: '
|
|
4164
|
+
const selectionNodes = timelineInfo.hasSelection && timelineInfo.selectionStartPercent !== null && timelineInfo.selectionEndPercent !== null ? [{
|
|
4165
|
+
childCount: 0,
|
|
4166
|
+
className: 'ChatDebugViewTimelineSelectionRange',
|
|
4167
|
+
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};width:${formatPercent(timelineInfo.selectionEndPercent - timelineInfo.selectionStartPercent)};`,
|
|
4168
|
+
type: Div
|
|
4169
|
+
}, {
|
|
4170
|
+
childCount: 0,
|
|
4171
|
+
className: 'ChatDebugViewTimelineSelectionMarker ChatDebugViewTimelineSelectionMarkerStart',
|
|
4172
|
+
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};`,
|
|
3020
4173
|
type: Div
|
|
3021
4174
|
}, {
|
|
4175
|
+
childCount: 0,
|
|
4176
|
+
className: 'ChatDebugViewTimelineSelectionMarker ChatDebugViewTimelineSelectionMarkerEnd',
|
|
4177
|
+
style: `left:${formatPercent(timelineInfo.selectionEndPercent)};`,
|
|
4178
|
+
type: Div
|
|
4179
|
+
}] : [];
|
|
4180
|
+
return [{
|
|
3022
4181
|
childCount: 2,
|
|
3023
|
-
className: '
|
|
4182
|
+
className: 'ChatDebugViewTimeline',
|
|
3024
4183
|
type: Div
|
|
3025
4184
|
}, {
|
|
3026
4185
|
childCount: 1,
|
|
3027
|
-
className: '
|
|
4186
|
+
className: 'ChatDebugViewTimelineTop',
|
|
3028
4187
|
type: Div
|
|
3029
|
-
},
|
|
4188
|
+
}, {
|
|
3030
4189
|
childCount: 1,
|
|
3031
4190
|
className: 'ChatDebugViewTimelineSummary',
|
|
3032
4191
|
type: Div
|
|
3033
|
-
}, text(getTimelineSummary(timelineEvents,
|
|
3034
|
-
childCount: 1,
|
|
3035
|
-
className: 'ChatDebugViewTimelineControls',
|
|
3036
|
-
type: Div
|
|
3037
|
-
}, {
|
|
4192
|
+
}, text(getTimelineSummary(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds)), {
|
|
3038
4193
|
childCount: 2,
|
|
3039
|
-
className:
|
|
3040
|
-
|
|
4194
|
+
className: 'ChatDebugViewTimelineInteractive',
|
|
4195
|
+
onDoubleClick: HandleTimelineDoubleClick,
|
|
4196
|
+
onPointerDown: HandleTimelinePointerDown,
|
|
4197
|
+
type: Div
|
|
3041
4198
|
}, {
|
|
3042
|
-
checked: !timelineInfo.hasSelection,
|
|
3043
|
-
childCount: 0,
|
|
3044
|
-
className: 'ChatDebugViewTimelinePresetInput',
|
|
3045
|
-
inputType: 'radio',
|
|
3046
|
-
name: TimelineRangePreset,
|
|
3047
|
-
onChange: HandleSimpleInput,
|
|
3048
|
-
type: Input,
|
|
3049
|
-
value: ''
|
|
3050
|
-
}, text('All'), {
|
|
3051
4199
|
childCount: timelineInfo.buckets.length,
|
|
3052
4200
|
className: 'ChatDebugViewTimelineBuckets',
|
|
3053
4201
|
type: Div
|
|
3054
|
-
}, ...timelineInfo.buckets.flatMap(
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
type: Label
|
|
3060
|
-
}, {
|
|
3061
|
-
checked: false,
|
|
3062
|
-
childCount: 0,
|
|
3063
|
-
className: 'ChatDebugViewTimelinePresetInput',
|
|
3064
|
-
inputType: 'radio',
|
|
3065
|
-
name: TimelineRangePreset,
|
|
3066
|
-
onChange: HandleSimpleInput,
|
|
3067
|
-
type: Input,
|
|
3068
|
-
value: presetValue
|
|
3069
|
-
}, {
|
|
3070
|
-
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
3071
|
-
className: `ChatDebugViewTimelineBucketBar${bucket.isSelected ? ' ChatDebugViewTimelineBucketBarSelected' : ''}`,
|
|
3072
|
-
type: Div
|
|
3073
|
-
}, ...(bucket.unitCount === 0 ? [{
|
|
3074
|
-
childCount: 0,
|
|
3075
|
-
className: 'ChatDebugViewTimelineBucketUnit ChatDebugViewTimelineBucketUnitEmpty',
|
|
3076
|
-
type: Div
|
|
3077
|
-
}] : Array.from({
|
|
3078
|
-
length: bucket.unitCount
|
|
3079
|
-
}).fill({
|
|
3080
|
-
childCount: 0,
|
|
3081
|
-
className: 'ChatDebugViewTimelineBucketUnit',
|
|
3082
|
-
type: Div
|
|
3083
|
-
}))];
|
|
3084
|
-
})];
|
|
4202
|
+
}, ...timelineInfo.buckets.flatMap(getBucketDom), {
|
|
4203
|
+
childCount: selectionNodes.length,
|
|
4204
|
+
className: 'ChatDebugViewTimelineSelectionOverlay',
|
|
4205
|
+
type: Div
|
|
4206
|
+
}, ...selectionNodes];
|
|
3085
4207
|
};
|
|
3086
4208
|
|
|
3087
|
-
const getDevtoolsDom = (events, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds) => {
|
|
4209
|
+
const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = 'No events have been found', timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
3088
4210
|
const rowNodes = getDevtoolsRows(events, selectedEventIndex);
|
|
3089
|
-
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds);
|
|
3090
|
-
const selectedEvent = selectedEventIndex === null ? undefined : events[selectedEventIndex];
|
|
4211
|
+
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
3091
4212
|
const selectedEventNodes = selectedEvent ? getEventNode(selectedEvent) : [];
|
|
3092
4213
|
const hasSelectedEvent = selectedEventNodes.length > 0;
|
|
3093
|
-
const
|
|
3094
|
-
const
|
|
3095
|
-
const detailsNodes =
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
}, {
|
|
3100
|
-
childCount: 2,
|
|
3101
|
-
className: 'ChatDebugViewDetailsTop',
|
|
3102
|
-
type: Div
|
|
3103
|
-
}, {
|
|
3104
|
-
childCount: 1,
|
|
3105
|
-
className: 'ChatDebugViewDetailsTitle',
|
|
3106
|
-
type: Div
|
|
3107
|
-
}, text('Details'), {
|
|
3108
|
-
childCount: 0,
|
|
3109
|
-
className: 'ChatDebugViewDetailsClose',
|
|
3110
|
-
inputType: 'checkbox',
|
|
3111
|
-
name: CloseDetails,
|
|
3112
|
-
onChange: HandleSimpleInput,
|
|
3113
|
-
type: Input,
|
|
3114
|
-
value: 'close'
|
|
3115
|
-
}, {
|
|
3116
|
-
childCount: selectedEventNodes.length,
|
|
3117
|
-
className: 'ChatDebugViewDetailsBody',
|
|
3118
|
-
type: Div
|
|
3119
|
-
}, ...selectedEventNodes] : [];
|
|
4214
|
+
const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableDom(rowNodes, events.length);
|
|
4215
|
+
const eventsClassName = getEventsClassName(hasSelectedEvent);
|
|
4216
|
+
const detailsNodes = getDetailsDom(selectedEventNodes, selectedEvent, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response);
|
|
4217
|
+
const sashNodes = getSashNodesDom(hasSelectedEvent);
|
|
4218
|
+
const splitChildCount = hasSelectedEvent ? 3 : 1;
|
|
4219
|
+
const mainChildCount = 1 + (timelineNodes.length > 0 ? 1 : 0);
|
|
3120
4220
|
return [{
|
|
3121
|
-
childCount:
|
|
4221
|
+
childCount: mainChildCount,
|
|
3122
4222
|
className: 'ChatDebugViewDevtoolsMain',
|
|
3123
4223
|
type: Div
|
|
3124
|
-
}, {
|
|
3125
|
-
childCount: eventsChildCount,
|
|
3126
|
-
className: eventsClassName,
|
|
3127
|
-
type: Div
|
|
3128
4224
|
}, ...timelineNodes, {
|
|
3129
|
-
childCount:
|
|
3130
|
-
className: '
|
|
3131
|
-
type: Div
|
|
3132
|
-
}, {
|
|
3133
|
-
childCount: 5,
|
|
3134
|
-
className: 'ChatDebugViewTableHeader',
|
|
4225
|
+
childCount: splitChildCount,
|
|
4226
|
+
className: 'ChatDebugViewDevtoolsSplit',
|
|
3135
4227
|
type: Div
|
|
3136
4228
|
}, {
|
|
3137
4229
|
childCount: 1,
|
|
3138
|
-
className:
|
|
3139
|
-
type: Div
|
|
3140
|
-
}, text('Type'), {
|
|
3141
|
-
childCount: 1,
|
|
3142
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellTime',
|
|
3143
|
-
type: Div
|
|
3144
|
-
}, text('Started'), {
|
|
3145
|
-
childCount: 1,
|
|
3146
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellTime',
|
|
3147
|
-
type: Div
|
|
3148
|
-
}, text('Ended'), {
|
|
3149
|
-
childCount: 1,
|
|
3150
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellDuration',
|
|
3151
|
-
type: Div
|
|
3152
|
-
}, text('Duration'), {
|
|
3153
|
-
childCount: 1,
|
|
3154
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellStatus',
|
|
3155
|
-
type: Div
|
|
3156
|
-
}, text('Status'), {
|
|
3157
|
-
childCount: rowNodes.length === 0 ? 1 : rowNodes.length,
|
|
3158
|
-
className: 'ChatDebugViewTableBody',
|
|
3159
|
-
onClick: HandleEventRowClick,
|
|
4230
|
+
className: eventsClassName,
|
|
3160
4231
|
type: Div
|
|
3161
|
-
}, ...
|
|
4232
|
+
}, ...tableNodes, ...sashNodes, ...detailsNodes];
|
|
3162
4233
|
};
|
|
3163
4234
|
|
|
3164
4235
|
const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
@@ -3172,12 +4243,13 @@ const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
|
3172
4243
|
type: Div
|
|
3173
4244
|
}, text(errorMessage || emptyMessage)] : eventNodes)];
|
|
3174
4245
|
};
|
|
3175
|
-
|
|
4246
|
+
|
|
4247
|
+
const getQuickFilterNodes = (eventCategoryFilter, eventCategoryFilterOptions) => {
|
|
3176
4248
|
return [{
|
|
3177
|
-
childCount:
|
|
4249
|
+
childCount: eventCategoryFilterOptions.length,
|
|
3178
4250
|
className: 'ChatDebugViewQuickFilters',
|
|
3179
4251
|
type: Div
|
|
3180
|
-
}, ...
|
|
4252
|
+
}, ...eventCategoryFilterOptions.flatMap(option => {
|
|
3181
4253
|
const isSelected = option.value === eventCategoryFilter;
|
|
3182
4254
|
return [{
|
|
3183
4255
|
childCount: 2,
|
|
@@ -3195,6 +4267,7 @@ const getQuickFilterNodes = eventCategoryFilter => {
|
|
|
3195
4267
|
}, text(option.label)];
|
|
3196
4268
|
})];
|
|
3197
4269
|
};
|
|
4270
|
+
|
|
3198
4271
|
const getTimelineFilterDescription = (timelineStartSeconds, timelineEndSeconds) => {
|
|
3199
4272
|
const trimmedStart = timelineStartSeconds.trim();
|
|
3200
4273
|
const trimmedEnd = timelineEndSeconds.trim();
|
|
@@ -3209,19 +4282,11 @@ const getTimelineFilterDescription = (timelineStartSeconds, timelineEndSeconds)
|
|
|
3209
4282
|
}
|
|
3210
4283
|
return '';
|
|
3211
4284
|
};
|
|
3212
|
-
|
|
4285
|
+
|
|
4286
|
+
const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eventCategoryFilterOptions, _showEventStreamFinishedEvents, _showInputEvents, _showResponsePartEvents, useDevtoolsLayout, selectedEvent, selectedEventIndex, timelineStartSeconds, timelineEndSeconds, timelineEvents, events, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
3213
4287
|
if (errorMessage) {
|
|
3214
|
-
return
|
|
3215
|
-
childCount: 1,
|
|
3216
|
-
className: 'ChatDebugView',
|
|
3217
|
-
type: Div
|
|
3218
|
-
}, {
|
|
3219
|
-
childCount: 1,
|
|
3220
|
-
className: 'ChatDebugViewError',
|
|
3221
|
-
type: Div
|
|
3222
|
-
}, text(errorMessage)];
|
|
4288
|
+
return getDebugErrorDom(errorMessage);
|
|
3223
4289
|
}
|
|
3224
|
-
const eventNodes = events.flatMap(getEventNode);
|
|
3225
4290
|
const trimmedFilterValue = filterValue.trim();
|
|
3226
4291
|
const filterDescriptionParts = [];
|
|
3227
4292
|
if (eventCategoryFilter !== All) {
|
|
@@ -3237,90 +4302,24 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, sho
|
|
|
3237
4302
|
const hasFilterValue = filterDescriptionParts.length > 0;
|
|
3238
4303
|
const filterDescription = filterDescriptionParts.join(' ');
|
|
3239
4304
|
const noFilteredEventsMessage = `no events found matching ${filterDescription}`;
|
|
3240
|
-
const
|
|
3241
|
-
const emptyMessage = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : 'No events';
|
|
4305
|
+
const emptyMessage = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : 'No events have been found';
|
|
3242
4306
|
const safeSelectedEventIndex = selectedEventIndex === null || selectedEventIndex < 0 || selectedEventIndex >= events.length ? null : selectedEventIndex;
|
|
3243
|
-
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds) : getLegacyEventsDom(errorMessage, emptyMessage,
|
|
3244
|
-
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter) : [];
|
|
3245
|
-
const
|
|
4307
|
+
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response) : getLegacyEventsDom(errorMessage, emptyMessage, events.flatMap(getEventNode));
|
|
4308
|
+
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter, eventCategoryFilterOptions) : [];
|
|
4309
|
+
const debugViewTopDom = getDebugViewTopDom(filterValue, useDevtoolsLayout, quickFilterNodes);
|
|
4310
|
+
const rootChildCount = 2;
|
|
3246
4311
|
return [{
|
|
3247
4312
|
childCount: rootChildCount,
|
|
3248
4313
|
className: useDevtoolsLayout ? 'ChatDebugView ChatDebugView--devtools' : 'ChatDebugView',
|
|
3249
4314
|
type: Div
|
|
3250
|
-
},
|
|
3251
|
-
childCount: 2,
|
|
3252
|
-
className: 'ChatDebugViewTop',
|
|
3253
|
-
type: Div
|
|
3254
|
-
}, {
|
|
3255
|
-
autocomplete: 'off',
|
|
3256
|
-
childCount: 0,
|
|
3257
|
-
className: 'InputBox',
|
|
3258
|
-
inputType: 'search',
|
|
3259
|
-
name: Filter,
|
|
3260
|
-
onInput: HandleFilterInput,
|
|
3261
|
-
placeholder: 'Filter events',
|
|
3262
|
-
type: Input,
|
|
3263
|
-
value: filterValue
|
|
3264
|
-
}, {
|
|
3265
|
-
childCount: 4,
|
|
3266
|
-
className: 'ChatDebugViewToggle',
|
|
3267
|
-
type: Div
|
|
3268
|
-
}, {
|
|
3269
|
-
childCount: 2,
|
|
3270
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3271
|
-
type: Label
|
|
3272
|
-
}, {
|
|
3273
|
-
checked: showEventStreamFinishedEvents,
|
|
3274
|
-
childCount: 0,
|
|
3275
|
-
inputType: 'checkbox',
|
|
3276
|
-
name: ShowEventStreamFinishedEvents,
|
|
3277
|
-
onChange: HandleInput,
|
|
3278
|
-
type: Input
|
|
3279
|
-
}, text('Show event stream finished events'), {
|
|
3280
|
-
childCount: 2,
|
|
3281
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3282
|
-
type: Label
|
|
3283
|
-
}, {
|
|
3284
|
-
checked: showInputEvents,
|
|
3285
|
-
childCount: 0,
|
|
3286
|
-
inputType: 'checkbox',
|
|
3287
|
-
name: ShowInputEvents,
|
|
3288
|
-
onChange: HandleInput,
|
|
3289
|
-
type: Input
|
|
3290
|
-
}, text('Show input events'), {
|
|
3291
|
-
childCount: 2,
|
|
3292
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3293
|
-
type: Label
|
|
3294
|
-
}, {
|
|
3295
|
-
checked: showResponsePartEvents,
|
|
3296
|
-
childCount: 0,
|
|
3297
|
-
inputType: 'checkbox',
|
|
3298
|
-
name: ShowResponsePartEvents,
|
|
3299
|
-
onChange: HandleInput,
|
|
3300
|
-
type: Input
|
|
3301
|
-
}, text('Show response part events'), {
|
|
3302
|
-
childCount: 2,
|
|
3303
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3304
|
-
type: Label
|
|
3305
|
-
}, {
|
|
3306
|
-
checked: useDevtoolsLayout,
|
|
3307
|
-
childCount: 0,
|
|
3308
|
-
inputType: 'checkbox',
|
|
3309
|
-
name: UseDevtoolsLayout,
|
|
3310
|
-
onChange: HandleInput,
|
|
3311
|
-
type: Input
|
|
3312
|
-
}, text('Use devtools layout'), ...quickFilterNodes, {
|
|
3313
|
-
childCount: 1,
|
|
3314
|
-
className: 'ChatDebugViewEventCount',
|
|
3315
|
-
type: Div
|
|
3316
|
-
}, text(eventCountText), ...contentNodes];
|
|
4315
|
+
}, ...debugViewTopDom, ...contentNodes];
|
|
3317
4316
|
};
|
|
3318
4317
|
|
|
3319
4318
|
const withSessionEventIds = events => {
|
|
3320
4319
|
return events.map((event, index) => {
|
|
3321
4320
|
return {
|
|
3322
4321
|
...event,
|
|
3323
|
-
eventId: index + 1
|
|
4322
|
+
eventId: typeof event.eventId === 'number' ? event.eventId : index + 1
|
|
3324
4323
|
};
|
|
3325
4324
|
});
|
|
3326
4325
|
};
|
|
@@ -3328,9 +4327,9 @@ const renderItems = (oldState, newState) => {
|
|
|
3328
4327
|
if (newState.initial) {
|
|
3329
4328
|
return [SetDom2, newState.uid, []];
|
|
3330
4329
|
}
|
|
3331
|
-
const timelineEvents =
|
|
4330
|
+
const timelineEvents = getTimelineEvents(newState);
|
|
3332
4331
|
const filteredEvents = filterEventsByTimelineRange(timelineEvents, newState.timelineStartSeconds, newState.timelineEndSeconds);
|
|
3333
|
-
const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, newState.eventCategoryFilter, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, withSessionEventIds(timelineEvents), withSessionEventIds(filteredEvents));
|
|
4332
|
+
const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, newState.eventCategoryFilter, newState.eventCategoryFilterOptions, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEvent, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, withSessionEventIds(timelineEvents), withSessionEventIds(filteredEvents), newState.timelineSelectionActive, newState.timelineSelectionAnchorSeconds, newState.timelineSelectionFocusSeconds, newState.selectedDetailTab);
|
|
3334
4333
|
return [SetDom2, newState.uid, dom];
|
|
3335
4334
|
};
|
|
3336
4335
|
|
|
@@ -3379,6 +4378,10 @@ const renderEventListeners = () => {
|
|
|
3379
4378
|
return [{
|
|
3380
4379
|
name: HandleEventRowClick,
|
|
3381
4380
|
params: ['handleEventRowClick', 'event.target.dataset.index']
|
|
4381
|
+
}, {
|
|
4382
|
+
name: HandleTableBodyContextMenu,
|
|
4383
|
+
params: ['handleTableBodyContextMenu'],
|
|
4384
|
+
preventDefault: true
|
|
3382
4385
|
}, {
|
|
3383
4386
|
name: HandleFilterInput,
|
|
3384
4387
|
params: ['handleInput', TargetName, TargetValue]
|
|
@@ -3388,6 +4391,29 @@ const renderEventListeners = () => {
|
|
|
3388
4391
|
}, {
|
|
3389
4392
|
name: HandleSimpleInput,
|
|
3390
4393
|
params: ['handleInput', TargetName, TargetValue]
|
|
4394
|
+
}, {
|
|
4395
|
+
name: HandleSashPointerDown,
|
|
4396
|
+
params: ['handleSashPointerDown', ClientX, ClientY],
|
|
4397
|
+
trackPointerEvents: [HandleSashPointerMove, HandleSashPointerUp]
|
|
4398
|
+
}, {
|
|
4399
|
+
name: HandleSashPointerMove,
|
|
4400
|
+
params: ['handleSashPointerMove', ClientX, ClientY]
|
|
4401
|
+
}, {
|
|
4402
|
+
name: HandleSashPointerUp,
|
|
4403
|
+
params: ['handleSashPointerUp', ClientX, ClientY]
|
|
4404
|
+
}, {
|
|
4405
|
+
name: HandleTimelinePointerDown,
|
|
4406
|
+
params: ['handleTimelinePointerDown', ClientX],
|
|
4407
|
+
trackPointerEvents: [HandleTimelinePointerMove, HandleTimelinePointerUp]
|
|
4408
|
+
}, {
|
|
4409
|
+
name: HandleTimelinePointerMove,
|
|
4410
|
+
params: ['handleTimelinePointerMove', ClientX]
|
|
4411
|
+
}, {
|
|
4412
|
+
name: HandleTimelinePointerUp,
|
|
4413
|
+
params: ['handleTimelinePointerUp', ClientX]
|
|
4414
|
+
}, {
|
|
4415
|
+
name: HandleTimelineDoubleClick,
|
|
4416
|
+
params: ['handleTimelineDoubleClick']
|
|
3391
4417
|
}];
|
|
3392
4418
|
};
|
|
3393
4419
|
|
|
@@ -3395,11 +4421,25 @@ const rerender = state => {
|
|
|
3395
4421
|
return structuredClone(state);
|
|
3396
4422
|
};
|
|
3397
4423
|
|
|
3398
|
-
const
|
|
3399
|
-
|
|
4424
|
+
const handleResize = (state, dimensions) => {
|
|
4425
|
+
const nextState = {
|
|
3400
4426
|
...state,
|
|
3401
4427
|
...dimensions
|
|
3402
4428
|
};
|
|
4429
|
+
return {
|
|
4430
|
+
...nextState,
|
|
4431
|
+
tableWidth: clampTableWidth(nextState.width, state.tableWidth)
|
|
4432
|
+
};
|
|
4433
|
+
};
|
|
4434
|
+
|
|
4435
|
+
const isResizeDimensions = value => {
|
|
4436
|
+
return typeof value === 'object' && value !== null;
|
|
4437
|
+
};
|
|
4438
|
+
const resize = (state, dimensions) => {
|
|
4439
|
+
if (!isResizeDimensions(dimensions)) {
|
|
4440
|
+
return state;
|
|
4441
|
+
}
|
|
4442
|
+
return handleResize(state, dimensions);
|
|
3403
4443
|
};
|
|
3404
4444
|
|
|
3405
4445
|
const saveState = state => {
|
|
@@ -3407,13 +4447,11 @@ const saveState = state => {
|
|
|
3407
4447
|
eventCategoryFilter,
|
|
3408
4448
|
filterValue,
|
|
3409
4449
|
height,
|
|
4450
|
+
selectedEventId,
|
|
3410
4451
|
sessionId,
|
|
3411
|
-
|
|
3412
|
-
showInputEvents,
|
|
3413
|
-
showResponsePartEvents,
|
|
4452
|
+
tableWidth,
|
|
3414
4453
|
timelineEndSeconds,
|
|
3415
4454
|
timelineStartSeconds,
|
|
3416
|
-
useDevtoolsLayout,
|
|
3417
4455
|
width,
|
|
3418
4456
|
x,
|
|
3419
4457
|
y
|
|
@@ -3422,13 +4460,11 @@ const saveState = state => {
|
|
|
3422
4460
|
eventCategoryFilter,
|
|
3423
4461
|
filterValue,
|
|
3424
4462
|
height,
|
|
4463
|
+
selectedEventId,
|
|
3425
4464
|
sessionId,
|
|
3426
|
-
|
|
3427
|
-
showInputEvents,
|
|
3428
|
-
showResponsePartEvents,
|
|
4465
|
+
tableWidth,
|
|
3429
4466
|
timelineEndSeconds,
|
|
3430
4467
|
timelineStartSeconds,
|
|
3431
|
-
useDevtoolsLayout,
|
|
3432
4468
|
width,
|
|
3433
4469
|
x,
|
|
3434
4470
|
y
|
|
@@ -3441,17 +4477,50 @@ const setEvents = (state, events) => {
|
|
|
3441
4477
|
errorMessage: '',
|
|
3442
4478
|
events,
|
|
3443
4479
|
initial: false,
|
|
4480
|
+
selectedEvent: null,
|
|
4481
|
+
selectedEventId: null,
|
|
3444
4482
|
selectedEventIndex: null
|
|
3445
4483
|
};
|
|
3446
4484
|
};
|
|
3447
4485
|
|
|
4486
|
+
const setIndexedDbSupportForTest = supported => {
|
|
4487
|
+
return setIndexedDbSupportOverride(supported);
|
|
4488
|
+
};
|
|
4489
|
+
|
|
3448
4490
|
const setSessionId = async (state, sessionId) => {
|
|
3449
|
-
const
|
|
4491
|
+
const result = await listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName);
|
|
4492
|
+
if (result.type === 'not-supported') {
|
|
4493
|
+
return {
|
|
4494
|
+
...state,
|
|
4495
|
+
errorMessage: getIndexedDbNotSupportedMessage(),
|
|
4496
|
+
events: [],
|
|
4497
|
+
initial: false,
|
|
4498
|
+
selectedEvent: null,
|
|
4499
|
+
selectedEventId: null,
|
|
4500
|
+
sessionId
|
|
4501
|
+
};
|
|
4502
|
+
}
|
|
4503
|
+
if (result.type === 'error') {
|
|
4504
|
+
return {
|
|
4505
|
+
...state,
|
|
4506
|
+
errorMessage: getFailedToLoadMessage(sessionId),
|
|
4507
|
+
events: [],
|
|
4508
|
+
initial: false,
|
|
4509
|
+
selectedEvent: null,
|
|
4510
|
+
selectedEventId: null,
|
|
4511
|
+
sessionId
|
|
4512
|
+
};
|
|
4513
|
+
}
|
|
4514
|
+
const {
|
|
4515
|
+
events
|
|
4516
|
+
} = result;
|
|
3450
4517
|
return {
|
|
3451
4518
|
...state,
|
|
3452
4519
|
errorMessage: '',
|
|
3453
4520
|
events,
|
|
3454
4521
|
initial: false,
|
|
4522
|
+
selectedEvent: null,
|
|
4523
|
+
selectedEventId: null,
|
|
3455
4524
|
sessionId
|
|
3456
4525
|
};
|
|
3457
4526
|
};
|
|
@@ -3462,6 +4531,14 @@ const commandMap = {
|
|
|
3462
4531
|
'ChatDebug.getCommandIds': getCommandIds,
|
|
3463
4532
|
'ChatDebug.handleEventRowClick': wrapCommand(handleEventRowClick),
|
|
3464
4533
|
'ChatDebug.handleInput': wrapCommand(handleInput),
|
|
4534
|
+
'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
|
|
4535
|
+
'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
|
|
4536
|
+
'ChatDebug.handleSashPointerUp': wrapCommand(handleSashPointerUp),
|
|
4537
|
+
'ChatDebug.handleTableBodyContextMenu': wrapCommand(handleTableBodyContextMenu),
|
|
4538
|
+
'ChatDebug.handleTimelineDoubleClick': wrapCommand(handleTimelineDoubleClick),
|
|
4539
|
+
'ChatDebug.handleTimelinePointerDown': wrapCommand(handleTimelinePointerDown),
|
|
4540
|
+
'ChatDebug.handleTimelinePointerMove': wrapCommand(handleTimelinePointerMove),
|
|
4541
|
+
'ChatDebug.handleTimelinePointerUp': wrapCommand(handleTimelinePointerUp),
|
|
3465
4542
|
'ChatDebug.loadContent': wrapCommand(loadContent),
|
|
3466
4543
|
'ChatDebug.loadContent2': wrapCommand(loadContent),
|
|
3467
4544
|
'ChatDebug.refresh': wrapCommand(refresh),
|
|
@@ -3471,6 +4548,7 @@ const commandMap = {
|
|
|
3471
4548
|
'ChatDebug.resize': wrapCommand(resize),
|
|
3472
4549
|
'ChatDebug.saveState': wrapGetter(saveState),
|
|
3473
4550
|
'ChatDebug.setEvents': wrapCommand(setEvents),
|
|
4551
|
+
'ChatDebug.setIndexedDbSupportForTest': setIndexedDbSupportForTest,
|
|
3474
4552
|
'ChatDebug.setSessionId': wrapCommand(setSessionId),
|
|
3475
4553
|
'ChatDebug.terminate': terminate
|
|
3476
4554
|
};
|