@lvce-editor/chat-debug-view 5.1.0 → 5.2.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 +739 -546
- package/package.json +1 -1
|
@@ -1026,7 +1026,7 @@ const {
|
|
|
1026
1026
|
const Response = 'response';
|
|
1027
1027
|
const Preview = 'preview';
|
|
1028
1028
|
const Timing = 'timing';
|
|
1029
|
-
const detailTabs = [
|
|
1029
|
+
const detailTabs = [Preview, Response, Timing];
|
|
1030
1030
|
const isDetailTab = value => {
|
|
1031
1031
|
return value === Response || value === Preview || value === Timing;
|
|
1032
1032
|
};
|
|
@@ -1171,399 +1171,85 @@ const diff2 = uid => {
|
|
|
1171
1171
|
return diff(oldState, newState);
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
return startedEvent.toolName === finishedEvent.toolName;
|
|
1177
|
-
}
|
|
1178
|
-
return true;
|
|
1174
|
+
const handleDetailsContextMenu = state => {
|
|
1175
|
+
return state;
|
|
1179
1176
|
};
|
|
1180
1177
|
|
|
1181
|
-
|
|
1182
|
-
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
|
|
1183
|
-
};
|
|
1178
|
+
// cspell:ignore IDBP
|
|
1184
1179
|
|
|
1185
1180
|
const startedEventType$1 = 'tool-execution-started';
|
|
1186
1181
|
const finishedEventType$1 = 'tool-execution-finished';
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1182
|
+
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1183
|
+
if (eventId < 1) {
|
|
1184
|
+
return undefined;
|
|
1185
|
+
}
|
|
1186
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1187
|
+
const index = store.index(sessionIdIndexName);
|
|
1188
|
+
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1189
|
+
if (keys.length < eventId) {
|
|
1190
|
+
return undefined;
|
|
1191
|
+
}
|
|
1192
|
+
const key = keys.at(-1);
|
|
1193
|
+
if (key === undefined) {
|
|
1194
|
+
return undefined;
|
|
1195
|
+
}
|
|
1196
|
+
const event = await store.get(key);
|
|
1197
|
+
return event;
|
|
1198
|
+
}
|
|
1199
|
+
const all = await store.getAll();
|
|
1200
|
+
const events = all.filter(event => event.sessionId === sessionId);
|
|
1201
|
+
return events[eventId - 1];
|
|
1195
1202
|
};
|
|
1196
|
-
|
|
1197
1203
|
const getTimestamp$1 = value => {
|
|
1198
1204
|
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1199
1205
|
};
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
const eventStableIds = new WeakMap();
|
|
1206
|
-
const eventStableIdState = {
|
|
1207
|
-
nextStableEventId: 1
|
|
1208
|
-
};
|
|
1209
|
-
|
|
1210
|
-
const getOrCreateStableEventId = event => {
|
|
1211
|
-
const existingStableEventId = eventStableIds.get(event);
|
|
1212
|
-
if (existingStableEventId) {
|
|
1213
|
-
return existingStableEventId;
|
|
1206
|
+
const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
|
|
1207
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1208
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1214
1209
|
}
|
|
1215
|
-
|
|
1216
|
-
eventStableIds.set(event, stableEventId);
|
|
1217
|
-
return stableEventId;
|
|
1218
|
-
};
|
|
1219
|
-
|
|
1220
|
-
const getStartedTimestamp = event => {
|
|
1221
|
-
return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1222
|
-
};
|
|
1223
|
-
|
|
1224
|
-
const setStableEventId = (event, stableEventId) => {
|
|
1225
|
-
eventStableIds.set(event, stableEventId);
|
|
1210
|
+
return true;
|
|
1226
1211
|
};
|
|
1227
|
-
|
|
1228
|
-
const
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1231
|
-
eventId
|
|
1232
|
-
} = startedEvent;
|
|
1233
|
-
const started = getStartedTimestamp(startedEvent);
|
|
1234
|
-
const mergedEvent = {
|
|
1212
|
+
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent, eventId) => {
|
|
1213
|
+
const ended = getTimestamp$1(finishedEvent.ended) ?? getTimestamp$1(finishedEvent.endTime) ?? getTimestamp$1(finishedEvent.timestamp);
|
|
1214
|
+
const started = getTimestamp$1(startedEvent.started) ?? getTimestamp$1(startedEvent.startTime) ?? getTimestamp$1(startedEvent.timestamp);
|
|
1215
|
+
return {
|
|
1235
1216
|
...startedEvent,
|
|
1236
1217
|
...finishedEvent,
|
|
1237
1218
|
...(ended === undefined ? {} : {
|
|
1238
1219
|
ended
|
|
1239
1220
|
}),
|
|
1240
|
-
|
|
1241
|
-
eventId
|
|
1242
|
-
}),
|
|
1221
|
+
eventId,
|
|
1243
1222
|
...(started === undefined ? {} : {
|
|
1244
1223
|
started
|
|
1245
1224
|
}),
|
|
1246
|
-
type:
|
|
1225
|
+
type: 'tool-execution'
|
|
1247
1226
|
};
|
|
1248
|
-
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1249
|
-
setStableEventId(mergedEvent, stableEventId);
|
|
1250
|
-
return mergedEvent;
|
|
1251
|
-
};
|
|
1252
|
-
|
|
1253
|
-
const getStableEventId = event => {
|
|
1254
|
-
return getOrCreateStableEventId(event);
|
|
1255
|
-
};
|
|
1256
|
-
|
|
1257
|
-
const collapseToolExecutionEvents = events => {
|
|
1258
|
-
const collapsedEvents = [];
|
|
1259
|
-
for (let i = 0; i < events.length; i++) {
|
|
1260
|
-
const event = events[i];
|
|
1261
|
-
if (isToolExecutionStartedEvent(event)) {
|
|
1262
|
-
const nextEvent = events[i + 1];
|
|
1263
|
-
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1264
|
-
collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
|
|
1265
|
-
i++;
|
|
1266
|
-
continue;
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
collapsedEvents.push(event);
|
|
1270
|
-
}
|
|
1271
|
-
return collapsedEvents;
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
|
-
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1275
|
-
return events.filter(event => {
|
|
1276
|
-
if (!showInputEvents && event.type === 'handle-input') {
|
|
1277
|
-
return false;
|
|
1278
|
-
}
|
|
1279
|
-
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1280
|
-
return false;
|
|
1281
|
-
}
|
|
1282
|
-
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1283
|
-
return false;
|
|
1284
|
-
}
|
|
1285
|
-
// hide session creation events by default — not useful in the debug view
|
|
1286
|
-
if (event.type === 'chat-session-created') {
|
|
1287
|
-
return false;
|
|
1288
|
-
}
|
|
1289
|
-
return true;
|
|
1290
|
-
});
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
|
-
const isNetworkEvent = event => {
|
|
1294
|
-
const normalizedType = event.type.toLowerCase();
|
|
1295
|
-
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1296
|
-
};
|
|
1297
|
-
|
|
1298
|
-
const isStreamEvent = event => {
|
|
1299
|
-
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1300
1227
|
};
|
|
1301
|
-
|
|
1302
|
-
const
|
|
1303
|
-
|
|
1304
|
-
return event.type.startsWith(toolEventTypePrefix);
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
const isUiEvent = event => {
|
|
1308
|
-
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1309
|
-
};
|
|
1310
|
-
|
|
1311
|
-
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1312
|
-
switch (eventCategoryFilter) {
|
|
1313
|
-
case Network:
|
|
1314
|
-
return isNetworkEvent(event);
|
|
1315
|
-
case Stream:
|
|
1316
|
-
return isStreamEvent(event);
|
|
1317
|
-
case Tools:
|
|
1318
|
-
return isToolEvent(event);
|
|
1319
|
-
case Ui:
|
|
1320
|
-
return isUiEvent(event);
|
|
1321
|
-
default:
|
|
1322
|
-
return true;
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
|
-
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1327
|
-
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1328
|
-
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
1329
|
-
const parsedFilter = parseFilterValue(filterValue);
|
|
1330
|
-
const activeEventCategoryFilter = parsedFilter.eventCategoryFilter === All ? eventCategoryFilter : parsedFilter.eventCategoryFilter;
|
|
1331
|
-
const filteredByCategory = collapsedEvents.filter(event => matchesEventCategoryFilter(event, activeEventCategoryFilter));
|
|
1332
|
-
const {
|
|
1333
|
-
filterText
|
|
1334
|
-
} = parsedFilter;
|
|
1335
|
-
if (!filterText) {
|
|
1336
|
-
return filteredByCategory;
|
|
1337
|
-
}
|
|
1338
|
-
return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
|
|
1339
|
-
};
|
|
1340
|
-
|
|
1341
|
-
const toTimeNumber = value => {
|
|
1342
|
-
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1343
|
-
return value;
|
|
1344
|
-
}
|
|
1345
|
-
if (typeof value === 'string') {
|
|
1346
|
-
const timestamp = Date.parse(value);
|
|
1347
|
-
if (!Number.isNaN(timestamp)) {
|
|
1348
|
-
return timestamp;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
return undefined;
|
|
1352
|
-
};
|
|
1353
|
-
|
|
1354
|
-
const getEventTime = event => {
|
|
1355
|
-
return toTimeNumber(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
1356
|
-
};
|
|
1357
|
-
|
|
1358
|
-
const maxBarUnits = 8;
|
|
1359
|
-
const parseTimelineSeconds = value => {
|
|
1360
|
-
const trimmed = value.trim();
|
|
1361
|
-
if (!trimmed) {
|
|
1362
|
-
return undefined;
|
|
1363
|
-
}
|
|
1364
|
-
const parsed = Number.parseFloat(trimmed);
|
|
1365
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
1228
|
+
const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
|
|
1229
|
+
const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
|
|
1230
|
+
if (!event) {
|
|
1366
1231
|
return undefined;
|
|
1367
1232
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
};
|
|
1373
|
-
const getEventsWithTime = events => {
|
|
1374
|
-
return events.flatMap(event => {
|
|
1375
|
-
const time = getEventTime(event);
|
|
1376
|
-
if (time === undefined) {
|
|
1377
|
-
return [];
|
|
1378
|
-
}
|
|
1379
|
-
return [{
|
|
1380
|
-
event,
|
|
1381
|
-
time
|
|
1382
|
-
}];
|
|
1383
|
-
});
|
|
1384
|
-
};
|
|
1385
|
-
const getTimelineDurationSeconds = events => {
|
|
1386
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1387
|
-
if (eventsWithTime.length === 0) {
|
|
1388
|
-
return 0;
|
|
1233
|
+
if (summaryType !== 'tool-execution') {
|
|
1234
|
+
return {
|
|
1235
|
+
...event,
|
|
1236
|
+
eventId
|
|
1237
|
+
};
|
|
1389
1238
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
if (durationSeconds <= 0) {
|
|
1396
|
-
return 0;
|
|
1239
|
+
if (event.type !== startedEventType$1) {
|
|
1240
|
+
return {
|
|
1241
|
+
...event,
|
|
1242
|
+
eventId
|
|
1243
|
+
};
|
|
1397
1244
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1401
|
-
const parsedStart = parseTimelineSeconds(startValue);
|
|
1402
|
-
const parsedEnd = parseTimelineSeconds(endValue);
|
|
1403
|
-
if (parsedStart === undefined && parsedEnd === undefined) {
|
|
1245
|
+
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1246
|
+
if (!nextEvent || nextEvent.type !== finishedEventType$1 || nextEvent.sessionId !== sessionId || !hasMatchingToolName$1(event, nextEvent)) {
|
|
1404
1247
|
return {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
startSeconds: null
|
|
1248
|
+
...event,
|
|
1249
|
+
eventId
|
|
1408
1250
|
};
|
|
1409
1251
|
}
|
|
1410
|
-
|
|
1411
|
-
const rawEnd = parsedEnd ?? durationSeconds;
|
|
1412
|
-
const normalizedStart = Math.max(0, Math.min(durationSeconds, Math.min(rawStart, rawEnd)));
|
|
1413
|
-
const normalizedEnd = Math.max(0, Math.min(durationSeconds, Math.max(rawStart, rawEnd)));
|
|
1414
|
-
return {
|
|
1415
|
-
endSeconds: roundSeconds(normalizedEnd),
|
|
1416
|
-
hasSelection: true,
|
|
1417
|
-
startSeconds: roundSeconds(normalizedStart)
|
|
1418
|
-
};
|
|
1419
|
-
};
|
|
1420
|
-
const filterEventsByTimelineRange = (events, startValue, endValue) => {
|
|
1421
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1422
|
-
if (eventsWithTime.length === 0) {
|
|
1423
|
-
return events;
|
|
1424
|
-
}
|
|
1425
|
-
const baseTime = eventsWithTime[0].time;
|
|
1426
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1427
|
-
const durationSeconds = roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1428
|
-
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1429
|
-
if (!range.hasSelection || range.startSeconds === null || range.endSeconds === null) {
|
|
1430
|
-
return events;
|
|
1431
|
-
}
|
|
1432
|
-
const startTime = baseTime + range.startSeconds * 1000;
|
|
1433
|
-
const endTime = baseTime + range.endSeconds * 1000;
|
|
1434
|
-
return eventsWithTime.filter(item => item.time >= startTime && item.time <= endTime).map(item => item.event);
|
|
1435
|
-
};
|
|
1436
|
-
const getTimelineInfo = (events, startValue, endValue) => {
|
|
1437
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1438
|
-
if (eventsWithTime.length === 0) {
|
|
1439
|
-
return {
|
|
1440
|
-
buckets: [],
|
|
1441
|
-
durationSeconds: 0,
|
|
1442
|
-
endSeconds: null,
|
|
1443
|
-
hasSelection: false,
|
|
1444
|
-
selectionEndPercent: null,
|
|
1445
|
-
selectionStartPercent: null,
|
|
1446
|
-
startSeconds: null
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
const baseTime = eventsWithTime[0].time;
|
|
1450
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1451
|
-
const durationMs = Math.max(0, lastTime - baseTime);
|
|
1452
|
-
const durationSeconds = roundSeconds(durationMs / 1000);
|
|
1453
|
-
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1454
|
-
const bucketCount = durationSeconds === 0 ? 1 : Math.max(12, Math.min(48, Math.ceil(durationSeconds)));
|
|
1455
|
-
const bucketDurationMs = durationMs === 0 ? 1000 : durationMs / bucketCount;
|
|
1456
|
-
const counts = Array.from({
|
|
1457
|
-
length: bucketCount
|
|
1458
|
-
}).fill(0);
|
|
1459
|
-
for (const item of eventsWithTime) {
|
|
1460
|
-
const offsetMs = item.time - baseTime;
|
|
1461
|
-
const index = durationMs === 0 ? 0 : Math.min(bucketCount - 1, Math.floor(offsetMs / durationMs * bucketCount));
|
|
1462
|
-
counts[index] += 1;
|
|
1463
|
-
}
|
|
1464
|
-
const maxCount = Math.max(...counts);
|
|
1465
|
-
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1466
|
-
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1467
|
-
const buckets = counts.map((count, index) => {
|
|
1468
|
-
const bucketStartMs = index * bucketDurationMs;
|
|
1469
|
-
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
1470
|
-
const hasSelection = range.hasSelection && range.startSeconds !== null && range.endSeconds !== null;
|
|
1471
|
-
const selectionStartMs = hasSelection ? range.startSeconds * 1000 : 0;
|
|
1472
|
-
const selectionEndMs = hasSelection ? range.endSeconds * 1000 : 0;
|
|
1473
|
-
return {
|
|
1474
|
-
count,
|
|
1475
|
-
endSeconds: roundSeconds(bucketEndMs / 1000),
|
|
1476
|
-
isSelected: hasSelection && bucketEndMs >= selectionStartMs && bucketStartMs <= selectionEndMs,
|
|
1477
|
-
startSeconds: roundSeconds(bucketStartMs / 1000),
|
|
1478
|
-
unitCount: count === 0 ? 0 : Math.max(1, Math.round(count / maxCount * maxBarUnits))
|
|
1479
|
-
};
|
|
1480
|
-
});
|
|
1481
|
-
return {
|
|
1482
|
-
buckets,
|
|
1483
|
-
durationSeconds,
|
|
1484
|
-
endSeconds: range.endSeconds,
|
|
1485
|
-
hasSelection: range.hasSelection,
|
|
1486
|
-
selectionEndPercent,
|
|
1487
|
-
selectionStartPercent,
|
|
1488
|
-
startSeconds: range.startSeconds
|
|
1489
|
-
};
|
|
1490
|
-
};
|
|
1491
|
-
|
|
1492
|
-
// cspell:ignore IDBP
|
|
1493
|
-
|
|
1494
|
-
const startedEventType = 'tool-execution-started';
|
|
1495
|
-
const finishedEventType = 'tool-execution-finished';
|
|
1496
|
-
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1497
|
-
if (eventId < 1) {
|
|
1498
|
-
return undefined;
|
|
1499
|
-
}
|
|
1500
|
-
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1501
|
-
const index = store.index(sessionIdIndexName);
|
|
1502
|
-
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1503
|
-
if (keys.length < eventId) {
|
|
1504
|
-
return undefined;
|
|
1505
|
-
}
|
|
1506
|
-
const key = keys.at(-1);
|
|
1507
|
-
if (key === undefined) {
|
|
1508
|
-
return undefined;
|
|
1509
|
-
}
|
|
1510
|
-
const event = await store.get(key);
|
|
1511
|
-
return event;
|
|
1512
|
-
}
|
|
1513
|
-
const all = await store.getAll();
|
|
1514
|
-
const events = all.filter(event => event.sessionId === sessionId);
|
|
1515
|
-
return events[eventId - 1];
|
|
1516
|
-
};
|
|
1517
|
-
const getTimestamp = value => {
|
|
1518
|
-
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1519
|
-
};
|
|
1520
|
-
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1521
|
-
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1522
|
-
return startedEvent.toolName === finishedEvent.toolName;
|
|
1523
|
-
}
|
|
1524
|
-
return true;
|
|
1525
|
-
};
|
|
1526
|
-
const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
|
|
1527
|
-
const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
|
|
1528
|
-
const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
|
|
1529
|
-
return {
|
|
1530
|
-
...startedEvent,
|
|
1531
|
-
...finishedEvent,
|
|
1532
|
-
...(ended === undefined ? {} : {
|
|
1533
|
-
ended
|
|
1534
|
-
}),
|
|
1535
|
-
eventId,
|
|
1536
|
-
...(started === undefined ? {} : {
|
|
1537
|
-
started
|
|
1538
|
-
}),
|
|
1539
|
-
type: 'tool-execution'
|
|
1540
|
-
};
|
|
1541
|
-
};
|
|
1542
|
-
const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
|
|
1543
|
-
const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
|
|
1544
|
-
if (!event) {
|
|
1545
|
-
return undefined;
|
|
1546
|
-
}
|
|
1547
|
-
if (summaryType !== 'tool-execution') {
|
|
1548
|
-
return {
|
|
1549
|
-
...event,
|
|
1550
|
-
eventId
|
|
1551
|
-
};
|
|
1552
|
-
}
|
|
1553
|
-
if (event.type !== startedEventType) {
|
|
1554
|
-
return {
|
|
1555
|
-
...event,
|
|
1556
|
-
eventId
|
|
1557
|
-
};
|
|
1558
|
-
}
|
|
1559
|
-
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1560
|
-
if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
|
|
1561
|
-
return {
|
|
1562
|
-
...event,
|
|
1563
|
-
eventId
|
|
1564
|
-
};
|
|
1565
|
-
}
|
|
1566
|
-
return mergeToolExecutionEvents(event, nextEvent, eventId);
|
|
1252
|
+
return mergeToolExecutionEvents$1(event, nextEvent, eventId);
|
|
1567
1253
|
};
|
|
1568
1254
|
|
|
1569
1255
|
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
@@ -1787,84 +1473,388 @@ const cursorIteratorTraps = {
|
|
|
1787
1473
|
return cachedFunc;
|
|
1788
1474
|
}
|
|
1789
1475
|
};
|
|
1790
|
-
async function* iterate(...args) {
|
|
1791
|
-
// tslint:disable-next-line:no-this-assignment
|
|
1792
|
-
let cursor = this;
|
|
1793
|
-
if (!(cursor instanceof IDBCursor)) {
|
|
1794
|
-
cursor = await cursor.openCursor(...args);
|
|
1795
|
-
}
|
|
1796
|
-
if (!cursor) return;
|
|
1797
|
-
cursor = cursor;
|
|
1798
|
-
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
1799
|
-
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
1800
|
-
// Map this double-proxy back to the original, so other cursor methods work.
|
|
1801
|
-
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
1802
|
-
while (cursor) {
|
|
1803
|
-
yield proxiedCursor;
|
|
1804
|
-
// If one of the advancing methods was not called, call continue().
|
|
1805
|
-
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
1806
|
-
advanceResults.delete(proxiedCursor);
|
|
1476
|
+
async function* iterate(...args) {
|
|
1477
|
+
// tslint:disable-next-line:no-this-assignment
|
|
1478
|
+
let cursor = this;
|
|
1479
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
1480
|
+
cursor = await cursor.openCursor(...args);
|
|
1481
|
+
}
|
|
1482
|
+
if (!cursor) return;
|
|
1483
|
+
cursor = cursor;
|
|
1484
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
1485
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
1486
|
+
// Map this double-proxy back to the original, so other cursor methods work.
|
|
1487
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
1488
|
+
while (cursor) {
|
|
1489
|
+
yield proxiedCursor;
|
|
1490
|
+
// If one of the advancing methods was not called, call continue().
|
|
1491
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
1492
|
+
advanceResults.delete(proxiedCursor);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
function isIteratorProp(target, prop) {
|
|
1496
|
+
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
1497
|
+
}
|
|
1498
|
+
replaceTraps(oldTraps => ({
|
|
1499
|
+
...oldTraps,
|
|
1500
|
+
get(target, prop, receiver) {
|
|
1501
|
+
if (isIteratorProp(target, prop)) return iterate;
|
|
1502
|
+
return oldTraps.get(target, prop, receiver);
|
|
1503
|
+
},
|
|
1504
|
+
has(target, prop) {
|
|
1505
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
1506
|
+
}
|
|
1507
|
+
}));
|
|
1508
|
+
|
|
1509
|
+
const openDatabaseDependencies = {
|
|
1510
|
+
openDB: openDB
|
|
1511
|
+
};
|
|
1512
|
+
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1513
|
+
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
const loadSelectedEventDependencies = {
|
|
1517
|
+
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1518
|
+
openDatabase: openDatabase
|
|
1519
|
+
};
|
|
1520
|
+
const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
|
|
1521
|
+
const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
1522
|
+
try {
|
|
1523
|
+
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
1527
|
+
const store = transaction.objectStore(eventStoreName);
|
|
1528
|
+
const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
|
|
1529
|
+
return event ?? null;
|
|
1530
|
+
} finally {
|
|
1531
|
+
database.close();
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1536
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1537
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1538
|
+
}
|
|
1539
|
+
return true;
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1543
|
+
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName(startedEvent, finishedEvent);
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
const startedEventType = 'tool-execution-started';
|
|
1547
|
+
const finishedEventType = 'tool-execution-finished';
|
|
1548
|
+
const mergedEventType = 'tool-execution';
|
|
1549
|
+
|
|
1550
|
+
const isToolExecutionFinishedEvent = event => {
|
|
1551
|
+
return event.type === finishedEventType;
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
const isToolExecutionStartedEvent = event => {
|
|
1555
|
+
return event.type === startedEventType;
|
|
1556
|
+
};
|
|
1557
|
+
|
|
1558
|
+
const getTimestamp = value => {
|
|
1559
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
const getEndedTimestamp = event => {
|
|
1563
|
+
return getTimestamp(event.ended) ?? getTimestamp(event.endTime) ?? getTimestamp(event.endTimestamp) ?? getTimestamp(event.timestamp);
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
const eventStableIds = new WeakMap();
|
|
1567
|
+
const eventStableIdState = {
|
|
1568
|
+
nextStableEventId: 1
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
const getOrCreateStableEventId = event => {
|
|
1572
|
+
const existingStableEventId = eventStableIds.get(event);
|
|
1573
|
+
if (existingStableEventId) {
|
|
1574
|
+
return existingStableEventId;
|
|
1575
|
+
}
|
|
1576
|
+
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1577
|
+
eventStableIds.set(event, stableEventId);
|
|
1578
|
+
return stableEventId;
|
|
1579
|
+
};
|
|
1580
|
+
|
|
1581
|
+
const getStartedTimestamp = event => {
|
|
1582
|
+
return getTimestamp(event.started) ?? getTimestamp(event.startTime) ?? getTimestamp(event.startTimestamp) ?? getTimestamp(event.timestamp);
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
const setStableEventId = (event, stableEventId) => {
|
|
1586
|
+
eventStableIds.set(event, stableEventId);
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
const mergeToolExecutionEvents = (startedEvent, finishedEvent) => {
|
|
1590
|
+
const ended = getEndedTimestamp(finishedEvent);
|
|
1591
|
+
const {
|
|
1592
|
+
eventId
|
|
1593
|
+
} = startedEvent;
|
|
1594
|
+
const started = getStartedTimestamp(startedEvent);
|
|
1595
|
+
const mergedEvent = {
|
|
1596
|
+
...startedEvent,
|
|
1597
|
+
...finishedEvent,
|
|
1598
|
+
...(ended === undefined ? {} : {
|
|
1599
|
+
ended
|
|
1600
|
+
}),
|
|
1601
|
+
...(eventId === undefined ? {} : {
|
|
1602
|
+
eventId
|
|
1603
|
+
}),
|
|
1604
|
+
...(started === undefined ? {} : {
|
|
1605
|
+
started
|
|
1606
|
+
}),
|
|
1607
|
+
type: mergedEventType
|
|
1608
|
+
};
|
|
1609
|
+
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1610
|
+
setStableEventId(mergedEvent, stableEventId);
|
|
1611
|
+
return mergedEvent;
|
|
1612
|
+
};
|
|
1613
|
+
|
|
1614
|
+
const getStableEventId = event => {
|
|
1615
|
+
return getOrCreateStableEventId(event);
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
const collapseToolExecutionEvents = events => {
|
|
1619
|
+
const collapsedEvents = [];
|
|
1620
|
+
for (let i = 0; i < events.length; i++) {
|
|
1621
|
+
const event = events[i];
|
|
1622
|
+
if (isToolExecutionStartedEvent(event)) {
|
|
1623
|
+
const nextEvent = events[i + 1];
|
|
1624
|
+
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1625
|
+
collapsedEvents.push(mergeToolExecutionEvents(event, nextEvent));
|
|
1626
|
+
i++;
|
|
1627
|
+
continue;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
collapsedEvents.push(event);
|
|
1631
|
+
}
|
|
1632
|
+
return collapsedEvents;
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1636
|
+
return events.filter(event => {
|
|
1637
|
+
if (!showInputEvents && event.type === 'handle-input') {
|
|
1638
|
+
return false;
|
|
1639
|
+
}
|
|
1640
|
+
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1641
|
+
return false;
|
|
1642
|
+
}
|
|
1643
|
+
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1644
|
+
return false;
|
|
1645
|
+
}
|
|
1646
|
+
// hide session creation events by default — not useful in the debug view
|
|
1647
|
+
if (event.type === 'chat-session-created') {
|
|
1648
|
+
return false;
|
|
1649
|
+
}
|
|
1650
|
+
return true;
|
|
1651
|
+
});
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1654
|
+
const isNetworkEvent = event => {
|
|
1655
|
+
const normalizedType = event.type.toLowerCase();
|
|
1656
|
+
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
const isStreamEvent = event => {
|
|
1660
|
+
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1661
|
+
};
|
|
1662
|
+
|
|
1663
|
+
const toolEventTypePrefix = 'tool-execution';
|
|
1664
|
+
const isToolEvent = event => {
|
|
1665
|
+
return event.type.startsWith(toolEventTypePrefix);
|
|
1666
|
+
};
|
|
1667
|
+
|
|
1668
|
+
const isUiEvent = event => {
|
|
1669
|
+
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1673
|
+
switch (eventCategoryFilter) {
|
|
1674
|
+
case Network:
|
|
1675
|
+
return isNetworkEvent(event);
|
|
1676
|
+
case Stream:
|
|
1677
|
+
return isStreamEvent(event);
|
|
1678
|
+
case Tools:
|
|
1679
|
+
return isToolEvent(event);
|
|
1680
|
+
case Ui:
|
|
1681
|
+
return isUiEvent(event);
|
|
1682
|
+
default:
|
|
1683
|
+
return true;
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1688
|
+
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1689
|
+
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
1690
|
+
const parsedFilter = parseFilterValue(filterValue);
|
|
1691
|
+
const activeEventCategoryFilter = parsedFilter.eventCategoryFilter === All ? eventCategoryFilter : parsedFilter.eventCategoryFilter;
|
|
1692
|
+
const filteredByCategory = collapsedEvents.filter(event => matchesEventCategoryFilter(event, activeEventCategoryFilter));
|
|
1693
|
+
const {
|
|
1694
|
+
filterText
|
|
1695
|
+
} = parsedFilter;
|
|
1696
|
+
if (!filterText) {
|
|
1697
|
+
return filteredByCategory;
|
|
1698
|
+
}
|
|
1699
|
+
return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
|
|
1700
|
+
};
|
|
1701
|
+
|
|
1702
|
+
const toTimeNumber = value => {
|
|
1703
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1704
|
+
return value;
|
|
1705
|
+
}
|
|
1706
|
+
if (typeof value === 'string') {
|
|
1707
|
+
const timestamp = Date.parse(value);
|
|
1708
|
+
if (!Number.isNaN(timestamp)) {
|
|
1709
|
+
return timestamp;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return undefined;
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
const getEventTime = event => {
|
|
1716
|
+
return toTimeNumber(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
const maxBarUnits = 8;
|
|
1720
|
+
const parseTimelineSeconds = value => {
|
|
1721
|
+
const trimmed = value.trim();
|
|
1722
|
+
if (!trimmed) {
|
|
1723
|
+
return undefined;
|
|
1724
|
+
}
|
|
1725
|
+
const parsed = Number.parseFloat(trimmed);
|
|
1726
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
1727
|
+
return undefined;
|
|
1728
|
+
}
|
|
1729
|
+
return parsed;
|
|
1730
|
+
};
|
|
1731
|
+
const roundSeconds = value => {
|
|
1732
|
+
return Number(value.toFixed(3));
|
|
1733
|
+
};
|
|
1734
|
+
const getEventsWithTime = events => {
|
|
1735
|
+
return events.flatMap(event => {
|
|
1736
|
+
const time = getEventTime(event);
|
|
1737
|
+
if (time === undefined) {
|
|
1738
|
+
return [];
|
|
1739
|
+
}
|
|
1740
|
+
return [{
|
|
1741
|
+
event,
|
|
1742
|
+
time
|
|
1743
|
+
}];
|
|
1744
|
+
});
|
|
1745
|
+
};
|
|
1746
|
+
const getTimelineDurationSeconds = events => {
|
|
1747
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1748
|
+
if (eventsWithTime.length === 0) {
|
|
1749
|
+
return 0;
|
|
1750
|
+
}
|
|
1751
|
+
const baseTime = eventsWithTime[0].time;
|
|
1752
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1753
|
+
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1754
|
+
};
|
|
1755
|
+
const getSelectionPercent = (value, durationSeconds) => {
|
|
1756
|
+
if (durationSeconds <= 0) {
|
|
1757
|
+
return 0;
|
|
1758
|
+
}
|
|
1759
|
+
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1760
|
+
};
|
|
1761
|
+
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1762
|
+
const parsedStart = parseTimelineSeconds(startValue);
|
|
1763
|
+
const parsedEnd = parseTimelineSeconds(endValue);
|
|
1764
|
+
if (parsedStart === undefined && parsedEnd === undefined) {
|
|
1765
|
+
return {
|
|
1766
|
+
endSeconds: null,
|
|
1767
|
+
hasSelection: false,
|
|
1768
|
+
startSeconds: null
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
const rawStart = parsedStart ?? 0;
|
|
1772
|
+
const rawEnd = parsedEnd ?? durationSeconds;
|
|
1773
|
+
const normalizedStart = Math.max(0, Math.min(durationSeconds, Math.min(rawStart, rawEnd)));
|
|
1774
|
+
const normalizedEnd = Math.max(0, Math.min(durationSeconds, Math.max(rawStart, rawEnd)));
|
|
1775
|
+
return {
|
|
1776
|
+
endSeconds: roundSeconds(normalizedEnd),
|
|
1777
|
+
hasSelection: true,
|
|
1778
|
+
startSeconds: roundSeconds(normalizedStart)
|
|
1779
|
+
};
|
|
1780
|
+
};
|
|
1781
|
+
const filterEventsByTimelineRange = (events, startValue, endValue) => {
|
|
1782
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1783
|
+
if (eventsWithTime.length === 0) {
|
|
1784
|
+
return events;
|
|
1807
1785
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
get(target, prop, receiver) {
|
|
1815
|
-
if (isIteratorProp(target, prop)) return iterate;
|
|
1816
|
-
return oldTraps.get(target, prop, receiver);
|
|
1817
|
-
},
|
|
1818
|
-
has(target, prop) {
|
|
1819
|
-
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
1786
|
+
const baseTime = eventsWithTime[0].time;
|
|
1787
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1788
|
+
const durationSeconds = roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1789
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1790
|
+
if (!range.hasSelection || range.startSeconds === null || range.endSeconds === null) {
|
|
1791
|
+
return events;
|
|
1820
1792
|
}
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
openDB: openDB
|
|
1825
|
-
};
|
|
1826
|
-
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1827
|
-
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1828
|
-
};
|
|
1829
|
-
|
|
1830
|
-
const loadSelectedEventDependencies = {
|
|
1831
|
-
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1832
|
-
openDatabase: openDatabase
|
|
1793
|
+
const startTime = baseTime + range.startSeconds * 1000;
|
|
1794
|
+
const endTime = baseTime + range.endSeconds * 1000;
|
|
1795
|
+
return eventsWithTime.filter(item => item.time >= startTime && item.time <= endTime).map(item => item.event);
|
|
1833
1796
|
};
|
|
1834
|
-
const
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1797
|
+
const getTimelineInfo = (events, startValue, endValue) => {
|
|
1798
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1799
|
+
if (eventsWithTime.length === 0) {
|
|
1800
|
+
return {
|
|
1801
|
+
buckets: [],
|
|
1802
|
+
durationSeconds: 0,
|
|
1803
|
+
endSeconds: null,
|
|
1804
|
+
hasSelection: false,
|
|
1805
|
+
selectionEndPercent: null,
|
|
1806
|
+
selectionStartPercent: null,
|
|
1807
|
+
startSeconds: null
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
const baseTime = eventsWithTime[0].time;
|
|
1811
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1812
|
+
const durationMs = Math.max(0, lastTime - baseTime);
|
|
1813
|
+
const durationSeconds = roundSeconds(durationMs / 1000);
|
|
1814
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1815
|
+
const bucketCount = durationSeconds === 0 ? 1 : Math.max(12, Math.min(48, Math.ceil(durationSeconds)));
|
|
1816
|
+
const bucketDurationMs = durationMs === 0 ? 1000 : durationMs / bucketCount;
|
|
1817
|
+
const counts = Array.from({
|
|
1818
|
+
length: bucketCount
|
|
1819
|
+
}).fill(0);
|
|
1820
|
+
for (const item of eventsWithTime) {
|
|
1821
|
+
const offsetMs = item.time - baseTime;
|
|
1822
|
+
const index = durationMs === 0 ? 0 : Math.min(bucketCount - 1, Math.floor(offsetMs / durationMs * bucketCount));
|
|
1823
|
+
counts[index] += 1;
|
|
1846
1824
|
}
|
|
1825
|
+
const maxCount = Math.max(...counts);
|
|
1826
|
+
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1827
|
+
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1828
|
+
const buckets = counts.map((count, index) => {
|
|
1829
|
+
const bucketStartMs = index * bucketDurationMs;
|
|
1830
|
+
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
1831
|
+
const hasSelection = range.hasSelection && range.startSeconds !== null && range.endSeconds !== null;
|
|
1832
|
+
const selectionStartMs = hasSelection ? range.startSeconds * 1000 : 0;
|
|
1833
|
+
const selectionEndMs = hasSelection ? range.endSeconds * 1000 : 0;
|
|
1834
|
+
return {
|
|
1835
|
+
count,
|
|
1836
|
+
endSeconds: roundSeconds(bucketEndMs / 1000),
|
|
1837
|
+
isSelected: hasSelection && bucketEndMs >= selectionStartMs && bucketStartMs <= selectionEndMs,
|
|
1838
|
+
startSeconds: roundSeconds(bucketStartMs / 1000),
|
|
1839
|
+
unitCount: count === 0 ? 0 : Math.max(1, Math.round(count / maxCount * maxBarUnits))
|
|
1840
|
+
};
|
|
1841
|
+
});
|
|
1842
|
+
return {
|
|
1843
|
+
buckets,
|
|
1844
|
+
durationSeconds,
|
|
1845
|
+
endSeconds: range.endSeconds,
|
|
1846
|
+
hasSelection: range.hasSelection,
|
|
1847
|
+
selectionEndPercent,
|
|
1848
|
+
selectionStartPercent,
|
|
1849
|
+
startSeconds: range.startSeconds
|
|
1850
|
+
};
|
|
1847
1851
|
};
|
|
1848
1852
|
|
|
1849
|
-
const handleEventRowClickDependencies = {
|
|
1850
|
-
loadSelectedEvent: loadSelectedEvent
|
|
1851
|
-
};
|
|
1852
1853
|
const getCurrentEvents$2 = state => {
|
|
1853
1854
|
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1854
1855
|
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1855
1856
|
};
|
|
1856
|
-
const
|
|
1857
|
-
const parsed = Number.parseInt(value, 10);
|
|
1858
|
-
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1859
|
-
return null;
|
|
1860
|
-
}
|
|
1861
|
-
return parsed;
|
|
1862
|
-
};
|
|
1863
|
-
const handleEventRowClick = async (state, value) => {
|
|
1864
|
-
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1865
|
-
if (selectedEventIndex === null) {
|
|
1866
|
-
return state;
|
|
1867
|
-
}
|
|
1857
|
+
const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
|
|
1868
1858
|
const currentEvents = getCurrentEvents$2(state);
|
|
1869
1859
|
const selectedEvent = currentEvents[selectedEventIndex];
|
|
1870
1860
|
if (!selectedEvent) {
|
|
@@ -1883,7 +1873,7 @@ const handleEventRowClick = async (state, value) => {
|
|
|
1883
1873
|
selectedEventIndex
|
|
1884
1874
|
};
|
|
1885
1875
|
}
|
|
1886
|
-
const selectedEventDetails = await
|
|
1876
|
+
const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
1887
1877
|
return {
|
|
1888
1878
|
...state,
|
|
1889
1879
|
selectedEvent: selectedEventDetails ?? selectedEvent,
|
|
@@ -1892,6 +1882,34 @@ const handleEventRowClick = async (state, value) => {
|
|
|
1892
1882
|
};
|
|
1893
1883
|
};
|
|
1894
1884
|
|
|
1885
|
+
const handleEventRowClickDependencies = {
|
|
1886
|
+
loadSelectedEvent: loadSelectedEvent
|
|
1887
|
+
};
|
|
1888
|
+
const isPrimaryButton = button => {
|
|
1889
|
+
return button === 0;
|
|
1890
|
+
};
|
|
1891
|
+
const parseSelectedEventIndex$1 = value => {
|
|
1892
|
+
const parsed = Number.parseInt(value, 10);
|
|
1893
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
return parsed;
|
|
1897
|
+
};
|
|
1898
|
+
const handleEventRowClick = async (state, value, button) => {
|
|
1899
|
+
if (!isPrimaryButton(button)) {
|
|
1900
|
+
return state;
|
|
1901
|
+
}
|
|
1902
|
+
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1903
|
+
if (selectedEventIndex === null) {
|
|
1904
|
+
return state;
|
|
1905
|
+
}
|
|
1906
|
+
return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
const handleHeaderContextMenu = state => {
|
|
1910
|
+
return state;
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1895
1913
|
const getBoolean = value => {
|
|
1896
1914
|
return value === true || value === 'true' || value === 'on' || value === '1';
|
|
1897
1915
|
};
|
|
@@ -2114,7 +2132,15 @@ const handleTimelineDoubleClick = state => {
|
|
|
2114
2132
|
};
|
|
2115
2133
|
|
|
2116
2134
|
const getTimelineEvents = state => {
|
|
2117
|
-
|
|
2135
|
+
const {
|
|
2136
|
+
eventCategoryFilter,
|
|
2137
|
+
events,
|
|
2138
|
+
filterValue,
|
|
2139
|
+
showEventStreamFinishedEvents,
|
|
2140
|
+
showInputEvents,
|
|
2141
|
+
showResponsePartEvents
|
|
2142
|
+
} = state;
|
|
2143
|
+
return getFilteredEvents(events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
2118
2144
|
};
|
|
2119
2145
|
|
|
2120
2146
|
const getTimelineLeft = state => {
|
|
@@ -2910,6 +2936,21 @@ const getCss = state => {
|
|
|
2910
2936
|
contain: content;
|
|
2911
2937
|
}
|
|
2912
2938
|
|
|
2939
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(1) {
|
|
2940
|
+
flex: 1 1 140px;
|
|
2941
|
+
min-width: 0;
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(2) {
|
|
2945
|
+
flex: 0 0 90px;
|
|
2946
|
+
justify-content: flex-end;
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(3) {
|
|
2950
|
+
flex: 0 0 96px;
|
|
2951
|
+
justify-content: flex-end;
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2913
2954
|
.ChatDebugViewTableBody {
|
|
2914
2955
|
display: flex;
|
|
2915
2956
|
flex-direction: column;
|
|
@@ -2939,8 +2980,12 @@ const getCss = state => {
|
|
|
2939
2980
|
|
|
2940
2981
|
.ChatDebugViewEventRow {
|
|
2941
2982
|
padding: 2px 8px;
|
|
2942
|
-
|
|
2943
|
-
cursor:
|
|
2983
|
+
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 92%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 8%);
|
|
2984
|
+
cursor: default;
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
.ChatDebugViewTableBody > .ChatDebugViewEventRow:nth-child(even) {
|
|
2988
|
+
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 84%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 16%);
|
|
2944
2989
|
}
|
|
2945
2990
|
|
|
2946
2991
|
.ChatDebugViewEventRow:hover {
|
|
@@ -2955,6 +3000,7 @@ const getCss = state => {
|
|
|
2955
3000
|
text-overflow: ellipsis;
|
|
2956
3001
|
white-space: nowrap;
|
|
2957
3002
|
min-width: 0;
|
|
3003
|
+
pointer-events: none;
|
|
2958
3004
|
contain: content;
|
|
2959
3005
|
}
|
|
2960
3006
|
|
|
@@ -3584,14 +3630,87 @@ const diffTree = (oldNodes, newNodes) => {
|
|
|
3584
3630
|
return removeTrailingNavigationPatches(patches);
|
|
3585
3631
|
};
|
|
3586
3632
|
|
|
3633
|
+
const ChatDebugView = 'ChatDebugView';
|
|
3634
|
+
const ChatDebugViewDevtools = 'ChatDebugView--devtools';
|
|
3635
|
+
const ChatDebugViewDetails = 'ChatDebugViewDetails';
|
|
3636
|
+
const ChatDebugViewDetailsBody = 'ChatDebugViewDetailsBody';
|
|
3637
|
+
const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
|
|
3638
|
+
const ChatDebugViewDetailsPanel = 'ChatDebugViewDetailsPanel';
|
|
3639
|
+
const ChatDebugViewDetailsTab = 'ChatDebugViewDetailsTab';
|
|
3640
|
+
const ChatDebugViewDetailsTabSelected = 'ChatDebugViewDetailsTabSelected';
|
|
3641
|
+
const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
|
|
3642
|
+
const ChatDebugViewDetailsTop = 'ChatDebugViewDetailsTop';
|
|
3643
|
+
const ChatDebugViewDevtoolsMain = 'ChatDebugViewDevtoolsMain';
|
|
3644
|
+
const ChatDebugViewDevtoolsSplit = 'ChatDebugViewDevtoolsSplit';
|
|
3645
|
+
const ChatDebugViewEmpty = 'ChatDebugViewEmpty';
|
|
3646
|
+
const ChatDebugViewError = 'ChatDebugViewError';
|
|
3647
|
+
const ChatDebugViewEvent = 'ChatDebugViewEvent';
|
|
3648
|
+
const ChatDebugViewEventLineContent = 'ChatDebugViewEventLineContent';
|
|
3649
|
+
const ChatDebugViewEventLineNumber = 'ChatDebugViewEventLineNumber';
|
|
3650
|
+
const ChatDebugViewEventRow = 'ChatDebugViewEventRow';
|
|
3651
|
+
const ChatDebugViewEventRowSelected = 'ChatDebugViewEventRowSelected';
|
|
3652
|
+
const ChatDebugViewEvents = 'ChatDebugViewEvents';
|
|
3653
|
+
const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
|
|
3654
|
+
const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
|
|
3655
|
+
const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
|
|
3656
|
+
const ChatDebugViewHeaderCell = 'ChatDebugViewHeaderCell';
|
|
3657
|
+
const ChatDebugViewQuickFilterInput = 'ChatDebugViewQuickFilterInput';
|
|
3658
|
+
const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
|
|
3659
|
+
const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
|
|
3660
|
+
const ChatDebugViewQuickFilters = 'ChatDebugViewQuickFilters';
|
|
3661
|
+
const ChatDebugViewSash = 'ChatDebugViewSash';
|
|
3662
|
+
const ChatDebugViewSashLine = 'ChatDebugViewSashLine';
|
|
3663
|
+
const ChatDebugViewTable = 'ChatDebugViewTable';
|
|
3664
|
+
const ChatDebugViewTableBody = 'ChatDebugViewTableBody';
|
|
3665
|
+
const ChatDebugViewTableHeader = 'ChatDebugViewTableHeader';
|
|
3666
|
+
const ChatDebugViewTableHeaderRow = 'ChatDebugViewTableHeaderRow';
|
|
3667
|
+
const ChatDebugViewTimeline = 'ChatDebugViewTimeline';
|
|
3668
|
+
const ChatDebugViewTimelineBucket = 'ChatDebugViewTimelineBucket';
|
|
3669
|
+
const ChatDebugViewTimelineBucketBar = 'ChatDebugViewTimelineBucketBar';
|
|
3670
|
+
const ChatDebugViewTimelineBucketBarSelected = 'ChatDebugViewTimelineBucketBarSelected';
|
|
3671
|
+
const ChatDebugViewTimelineBucketSelected = 'ChatDebugViewTimelineBucketSelected';
|
|
3672
|
+
const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
|
|
3673
|
+
const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
|
|
3674
|
+
const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
|
|
3675
|
+
const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
|
|
3676
|
+
const ChatDebugViewTimelinePresetInput = 'ChatDebugViewTimelinePresetInput';
|
|
3677
|
+
const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
|
|
3678
|
+
const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
|
|
3679
|
+
const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
|
|
3680
|
+
const ChatDebugViewTimelineSelectionOverlay = 'ChatDebugViewTimelineSelectionOverlay';
|
|
3681
|
+
const ChatDebugViewTimelineSelectionRange = 'ChatDebugViewTimelineSelectionRange';
|
|
3682
|
+
const ChatDebugViewTimelineSummary = 'ChatDebugViewTimelineSummary';
|
|
3683
|
+
const ChatDebugViewTimelineTop = 'ChatDebugViewTimelineTop';
|
|
3684
|
+
const ChatDebugViewTiming = 'ChatDebugViewTiming';
|
|
3685
|
+
const ChatDebugViewTimingLabel = 'ChatDebugViewTimingLabel';
|
|
3686
|
+
const ChatDebugViewTimingRow = 'ChatDebugViewTimingRow';
|
|
3687
|
+
const ChatDebugViewTimingValue = 'ChatDebugViewTimingValue';
|
|
3688
|
+
const ChatDebugViewTop = 'ChatDebugViewTop';
|
|
3689
|
+
const ChatDebugViewTopDevtools = 'ChatDebugViewTop--devtools';
|
|
3690
|
+
const ChatDebugViewCell = 'ChatDebugViewCell';
|
|
3691
|
+
const ChatDebugViewCellDuration = 'ChatDebugViewCellDuration';
|
|
3692
|
+
const ChatDebugViewCellStatus = 'ChatDebugViewCellStatus';
|
|
3693
|
+
const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
|
|
3694
|
+
const ChatDebugViewCellType = 'ChatDebugViewCellType';
|
|
3695
|
+
const InputBox = 'InputBox';
|
|
3696
|
+
const Row = 'row';
|
|
3697
|
+
const TokenBoolean = 'TokenBoolean';
|
|
3698
|
+
const TokenKey = 'TokenKey';
|
|
3699
|
+
const TokenNumeric = 'TokenNumeric';
|
|
3700
|
+
const TokenString = 'TokenString';
|
|
3701
|
+
const TokenText = 'TokenText';
|
|
3702
|
+
const joinClassNames = (...classNames) => {
|
|
3703
|
+
return classNames.filter(Boolean).join(' ');
|
|
3704
|
+
};
|
|
3705
|
+
|
|
3587
3706
|
const getDebugErrorDom = errorMessage => {
|
|
3588
3707
|
return [{
|
|
3589
3708
|
childCount: 1,
|
|
3590
|
-
className:
|
|
3709
|
+
className: ChatDebugView,
|
|
3591
3710
|
type: Div
|
|
3592
3711
|
}, {
|
|
3593
3712
|
childCount: 1,
|
|
3594
|
-
className:
|
|
3713
|
+
className: ChatDebugViewError,
|
|
3595
3714
|
type: Div
|
|
3596
3715
|
}, text(errorMessage)];
|
|
3597
3716
|
};
|
|
@@ -3600,25 +3719,29 @@ const HandleInput = 4;
|
|
|
3600
3719
|
const HandleFilterInput = 5;
|
|
3601
3720
|
const HandleSimpleInput = 6;
|
|
3602
3721
|
const HandleEventRowClick = 7;
|
|
3603
|
-
const
|
|
3604
|
-
const
|
|
3605
|
-
const
|
|
3606
|
-
const
|
|
3607
|
-
const
|
|
3608
|
-
const
|
|
3609
|
-
const
|
|
3610
|
-
const
|
|
3722
|
+
const HandleHeaderContextMenu = 8;
|
|
3723
|
+
const HandleSashPointerDown = 9;
|
|
3724
|
+
const HandleSashPointerMove = 10;
|
|
3725
|
+
const HandleSashPointerUp = 11;
|
|
3726
|
+
const HandleTableBodyContextMenu = 12;
|
|
3727
|
+
const HandleDetailsContextMenu = 13;
|
|
3728
|
+
const HandleTimelinePointerDown = 14;
|
|
3729
|
+
const HandleTimelinePointerMove = 15;
|
|
3730
|
+
const HandleTimelinePointerUp = 16;
|
|
3731
|
+
const HandleTimelineDoubleClick = 17;
|
|
3732
|
+
const HandleTableKeyDown = 18;
|
|
3611
3733
|
|
|
3612
3734
|
const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
|
|
3613
3735
|
if (useDevtoolsLayout) {
|
|
3614
3736
|
return [{
|
|
3615
3737
|
childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
|
|
3616
|
-
className:
|
|
3738
|
+
className: joinClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
|
|
3739
|
+
onContextMenu: HandleHeaderContextMenu,
|
|
3617
3740
|
type: Search
|
|
3618
3741
|
}, {
|
|
3619
3742
|
autocomplete: 'off',
|
|
3620
3743
|
childCount: 0,
|
|
3621
|
-
className:
|
|
3744
|
+
className: joinClassNames(InputBox, ChatDebugViewFilterInput, ChatDebugViewFilterInputDevtools),
|
|
3622
3745
|
inputType: 'search',
|
|
3623
3746
|
name: Filter,
|
|
3624
3747
|
onInput: HandleFilterInput,
|
|
@@ -3629,12 +3752,13 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
|
|
|
3629
3752
|
}
|
|
3630
3753
|
return [{
|
|
3631
3754
|
childCount: 1,
|
|
3632
|
-
className:
|
|
3755
|
+
className: ChatDebugViewTop,
|
|
3756
|
+
onContextMenu: HandleHeaderContextMenu,
|
|
3633
3757
|
type: Search
|
|
3634
3758
|
}, {
|
|
3635
3759
|
autocomplete: 'off',
|
|
3636
3760
|
childCount: 0,
|
|
3637
|
-
className:
|
|
3761
|
+
className: joinClassNames(InputBox, ChatDebugViewFilterInput),
|
|
3638
3762
|
inputType: 'search',
|
|
3639
3763
|
name: Filter,
|
|
3640
3764
|
onInput: HandleFilterInput,
|
|
@@ -3697,22 +3821,22 @@ const getStartText = event => {
|
|
|
3697
3821
|
const getTimingRowDom = (label, value) => {
|
|
3698
3822
|
return [{
|
|
3699
3823
|
childCount: 2,
|
|
3700
|
-
className:
|
|
3824
|
+
className: ChatDebugViewTimingRow,
|
|
3701
3825
|
type: Div
|
|
3702
3826
|
}, {
|
|
3703
3827
|
childCount: 1,
|
|
3704
|
-
className:
|
|
3828
|
+
className: ChatDebugViewTimingLabel,
|
|
3705
3829
|
type: Span
|
|
3706
3830
|
}, text(label), {
|
|
3707
3831
|
childCount: 1,
|
|
3708
|
-
className:
|
|
3832
|
+
className: ChatDebugViewTimingValue,
|
|
3709
3833
|
type: Span
|
|
3710
3834
|
}, text(value)];
|
|
3711
3835
|
};
|
|
3712
3836
|
const getTimingDetailsDom = event => {
|
|
3713
3837
|
return [{
|
|
3714
3838
|
childCount: 3,
|
|
3715
|
-
className:
|
|
3839
|
+
className: ChatDebugViewTiming,
|
|
3716
3840
|
type: Div
|
|
3717
3841
|
}, ...getTimingRowDom('Started', getStartText(event)), ...getTimingRowDom('Ended', getEndText(event)), ...getTimingRowDom('Duration', getDurationText(event))];
|
|
3718
3842
|
};
|
|
@@ -3730,7 +3854,7 @@ const getTabNodes = selectedDetailTab => {
|
|
|
3730
3854
|
'aria-controls': getPanelId(detailTab),
|
|
3731
3855
|
'aria-selected': isSelected,
|
|
3732
3856
|
childCount: 1,
|
|
3733
|
-
className: isSelected
|
|
3857
|
+
className: joinClassNames(ChatDebugViewDetailsTab, isSelected && ChatDebugViewDetailsTabSelected),
|
|
3734
3858
|
id: getTabId(detailTab),
|
|
3735
3859
|
name: DetailTab,
|
|
3736
3860
|
onChange: HandleSimpleInput,
|
|
@@ -3742,23 +3866,23 @@ const getTabNodes = selectedDetailTab => {
|
|
|
3742
3866
|
}, text(getDetailTabLabel(detailTab))];
|
|
3743
3867
|
});
|
|
3744
3868
|
};
|
|
3745
|
-
const getDetailsDom = (
|
|
3746
|
-
if (
|
|
3869
|
+
const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes, selectedEvent = null, selectedDetailTab = Response) => {
|
|
3870
|
+
if (previewEventNodes.length === 0 && responseEventNodes.length === 0) {
|
|
3747
3871
|
return [];
|
|
3748
3872
|
}
|
|
3749
|
-
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) :
|
|
3873
|
+
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) : selectedDetailTab === Preview ? previewEventNodes : responseEventNodes;
|
|
3750
3874
|
return [{
|
|
3751
3875
|
childCount: 2,
|
|
3752
|
-
className:
|
|
3876
|
+
className: ChatDebugViewDetails,
|
|
3753
3877
|
type: Div
|
|
3754
3878
|
}, {
|
|
3755
3879
|
childCount: 2,
|
|
3756
|
-
className:
|
|
3880
|
+
className: ChatDebugViewDetailsTop,
|
|
3757
3881
|
type: Div
|
|
3758
3882
|
}, {
|
|
3759
3883
|
'aria-label': 'Close details',
|
|
3760
3884
|
childCount: 0,
|
|
3761
|
-
className:
|
|
3885
|
+
className: ChatDebugViewDetailsClose,
|
|
3762
3886
|
name: CloseDetails,
|
|
3763
3887
|
onChange: HandleSimpleInput,
|
|
3764
3888
|
onClick: HandleSimpleInput,
|
|
@@ -3767,19 +3891,20 @@ const getDetailsDom = (selectedEventNodes, selectedEvent = null, selectedDetailT
|
|
|
3767
3891
|
}, {
|
|
3768
3892
|
'aria-label': 'Detail sections',
|
|
3769
3893
|
childCount: detailTabs.length,
|
|
3770
|
-
className:
|
|
3894
|
+
className: ChatDebugViewDetailsTabs,
|
|
3771
3895
|
role: 'tablist',
|
|
3772
3896
|
type: Div
|
|
3773
3897
|
}, ...getTabNodes(selectedDetailTab), {
|
|
3774
3898
|
childCount: 1,
|
|
3775
|
-
className:
|
|
3899
|
+
className: ChatDebugViewDetailsBody,
|
|
3776
3900
|
role: 'document',
|
|
3777
3901
|
type: Div
|
|
3778
3902
|
}, {
|
|
3779
3903
|
'aria-labelledby': getTabId(selectedDetailTab),
|
|
3780
3904
|
childCount: 1,
|
|
3781
|
-
className:
|
|
3905
|
+
className: ChatDebugViewDetailsPanel,
|
|
3782
3906
|
id: getPanelId(selectedDetailTab),
|
|
3907
|
+
onContextMenu: HandleDetailsContextMenu,
|
|
3783
3908
|
role: 'tabpanel',
|
|
3784
3909
|
type: Div
|
|
3785
3910
|
}, ...contentNodes];
|
|
@@ -3818,6 +3943,19 @@ const getEventTypeLabel = event => {
|
|
|
3818
3943
|
return `${event.type}, ${toolName}`;
|
|
3819
3944
|
};
|
|
3820
3945
|
|
|
3946
|
+
const isRecord = value => {
|
|
3947
|
+
return typeof value === 'object' && value !== null;
|
|
3948
|
+
};
|
|
3949
|
+
const isErrorStatusCode = value => {
|
|
3950
|
+
if (typeof value === 'number') {
|
|
3951
|
+
return value >= 400;
|
|
3952
|
+
}
|
|
3953
|
+
if (typeof value === 'string') {
|
|
3954
|
+
const parsedStatus = Number(value);
|
|
3955
|
+
return Number.isFinite(parsedStatus) && parsedStatus >= 400;
|
|
3956
|
+
}
|
|
3957
|
+
return false;
|
|
3958
|
+
};
|
|
3821
3959
|
const hasErrorStatus = event => {
|
|
3822
3960
|
if (event.type === 'error') {
|
|
3823
3961
|
return true;
|
|
@@ -3828,12 +3966,17 @@ const hasErrorStatus = event => {
|
|
|
3828
3966
|
const {
|
|
3829
3967
|
status
|
|
3830
3968
|
} = event;
|
|
3831
|
-
if (
|
|
3969
|
+
if (isErrorStatusCode(status)) {
|
|
3832
3970
|
return true;
|
|
3833
3971
|
}
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3972
|
+
const {
|
|
3973
|
+
result
|
|
3974
|
+
} = event;
|
|
3975
|
+
if (isRecord(result)) {
|
|
3976
|
+
if (isErrorStatusCode(result.status)) {
|
|
3977
|
+
return true;
|
|
3978
|
+
}
|
|
3979
|
+
if (typeof result.error === 'string' || typeof result.errorMessage === 'string' || typeof result.exception === 'string') {
|
|
3837
3980
|
return true;
|
|
3838
3981
|
}
|
|
3839
3982
|
}
|
|
@@ -3851,23 +3994,20 @@ const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
|
3851
3994
|
const rowIndex = String(i);
|
|
3852
3995
|
return [{
|
|
3853
3996
|
childCount: 3,
|
|
3854
|
-
className:
|
|
3997
|
+
className: joinClassNames(ChatDebugViewEventRow, isSelected && ChatDebugViewEventRowSelected),
|
|
3855
3998
|
'data-index': rowIndex,
|
|
3856
3999
|
type: Tr
|
|
3857
4000
|
}, {
|
|
3858
4001
|
childCount: 1,
|
|
3859
|
-
className:
|
|
3860
|
-
'data-index': rowIndex,
|
|
4002
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellType),
|
|
3861
4003
|
type: Td
|
|
3862
4004
|
}, text(getEventTypeLabel(event)), {
|
|
3863
4005
|
childCount: 1,
|
|
3864
|
-
className:
|
|
3865
|
-
'data-index': rowIndex,
|
|
4006
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellDuration),
|
|
3866
4007
|
type: Td
|
|
3867
4008
|
}, text(getDurationText(event)), {
|
|
3868
4009
|
childCount: 1,
|
|
3869
|
-
className:
|
|
3870
|
-
'data-index': rowIndex,
|
|
4010
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellStatus, isErrorStatus && ChatDebugViewCellStatusError),
|
|
3871
4011
|
type: Td
|
|
3872
4012
|
}, text(getStatusText(event))];
|
|
3873
4013
|
});
|
|
@@ -3876,7 +4016,7 @@ const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
|
3876
4016
|
const getEmptyStateDom = emptyMessage => {
|
|
3877
4017
|
return [{
|
|
3878
4018
|
childCount: 1,
|
|
3879
|
-
className:
|
|
4019
|
+
className: ChatDebugViewEmpty,
|
|
3880
4020
|
type: Div
|
|
3881
4021
|
}, text(emptyMessage)];
|
|
3882
4022
|
};
|
|
@@ -3926,32 +4066,32 @@ const getTokenSegments = json => {
|
|
|
3926
4066
|
while (lookAheadIndex < json.length && whitespaceRegex.test(json[lookAheadIndex])) {
|
|
3927
4067
|
lookAheadIndex++;
|
|
3928
4068
|
}
|
|
3929
|
-
const className = json[lookAheadIndex] === ':' ?
|
|
4069
|
+
const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
|
|
3930
4070
|
segments = pushToken(segments, className, tokenValue);
|
|
3931
4071
|
continue;
|
|
3932
4072
|
}
|
|
3933
4073
|
const numberMatch = numberRegex.exec(json.slice(i));
|
|
3934
4074
|
if (numberMatch) {
|
|
3935
|
-
segments = pushToken(segments,
|
|
4075
|
+
segments = pushToken(segments, TokenNumeric, numberMatch[0]);
|
|
3936
4076
|
i += numberMatch[0].length;
|
|
3937
4077
|
continue;
|
|
3938
4078
|
}
|
|
3939
4079
|
if (json.startsWith('true', i)) {
|
|
3940
|
-
segments = pushToken(segments,
|
|
4080
|
+
segments = pushToken(segments, TokenBoolean, 'true');
|
|
3941
4081
|
i += 4;
|
|
3942
4082
|
continue;
|
|
3943
4083
|
}
|
|
3944
4084
|
if (json.startsWith('false', i)) {
|
|
3945
|
-
segments = pushToken(segments,
|
|
4085
|
+
segments = pushToken(segments, TokenBoolean, 'false');
|
|
3946
4086
|
i += 5;
|
|
3947
4087
|
continue;
|
|
3948
4088
|
}
|
|
3949
4089
|
if (json.startsWith('null', i)) {
|
|
3950
|
-
segments = pushToken(segments,
|
|
4090
|
+
segments = pushToken(segments, TokenBoolean, 'null');
|
|
3951
4091
|
i += 4;
|
|
3952
4092
|
continue;
|
|
3953
4093
|
}
|
|
3954
|
-
segments = pushToken(segments,
|
|
4094
|
+
segments = pushToken(segments, TokenText, character);
|
|
3955
4095
|
i++;
|
|
3956
4096
|
}
|
|
3957
4097
|
return segments;
|
|
@@ -3961,7 +4101,7 @@ const getJsonLines = value => {
|
|
|
3961
4101
|
const json = JSON.stringify(value, null, 2);
|
|
3962
4102
|
if (!json) {
|
|
3963
4103
|
return [[{
|
|
3964
|
-
className:
|
|
4104
|
+
className: TokenText,
|
|
3965
4105
|
value: String(json)
|
|
3966
4106
|
}]];
|
|
3967
4107
|
}
|
|
@@ -4001,50 +4141,93 @@ const getLineNodes = lines => {
|
|
|
4001
4141
|
const lineContentNodes = getLineContentNodes(line);
|
|
4002
4142
|
return [{
|
|
4003
4143
|
childCount: 2,
|
|
4004
|
-
className:
|
|
4144
|
+
className: Row,
|
|
4005
4145
|
type: Div
|
|
4006
4146
|
}, {
|
|
4007
4147
|
childCount: 1,
|
|
4008
|
-
className:
|
|
4148
|
+
className: ChatDebugViewEventLineNumber,
|
|
4009
4149
|
type: Span
|
|
4010
4150
|
}, text(String(index + 1)), {
|
|
4011
4151
|
childCount: lineContentNodes.length / 2,
|
|
4012
|
-
className:
|
|
4152
|
+
className: ChatDebugViewEventLineContent,
|
|
4013
4153
|
type: Span
|
|
4014
4154
|
}, ...lineContentNodes];
|
|
4015
4155
|
});
|
|
4016
4156
|
};
|
|
4017
|
-
const
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4157
|
+
const isChatViewEvent = value => {
|
|
4158
|
+
return typeof value === 'object' && value !== null && typeof value.type === 'string';
|
|
4159
|
+
};
|
|
4160
|
+
const getEventNode = value => {
|
|
4161
|
+
const renderedValue = isChatViewEvent(value) ? {
|
|
4162
|
+
...value,
|
|
4163
|
+
type: getEventTypeLabel(value)
|
|
4164
|
+
} : value;
|
|
4165
|
+
const lines = getJsonLines(renderedValue);
|
|
4023
4166
|
const lineNodes = getLineNodes(lines);
|
|
4024
4167
|
return [{
|
|
4025
4168
|
childCount: lines.length,
|
|
4026
|
-
className:
|
|
4169
|
+
className: ChatDebugViewEvent,
|
|
4027
4170
|
type: Div
|
|
4028
4171
|
}, ...lineNodes];
|
|
4029
4172
|
};
|
|
4030
4173
|
|
|
4031
4174
|
const getEventsClassName = hasSelectedEvent => {
|
|
4032
|
-
const widthClassName =
|
|
4175
|
+
const widthClassName = joinClassNames(ChatDebugViewEvents, !hasSelectedEvent && ChatDebugViewEventsFullWidth);
|
|
4033
4176
|
return widthClassName;
|
|
4034
4177
|
};
|
|
4035
4178
|
|
|
4179
|
+
const hasOwn = (event, key) => {
|
|
4180
|
+
return Object.hasOwn(event, key);
|
|
4181
|
+
};
|
|
4182
|
+
const getPreviewName = event => {
|
|
4183
|
+
if (typeof event.name === 'string' && event.name) {
|
|
4184
|
+
return event.name;
|
|
4185
|
+
}
|
|
4186
|
+
if (typeof event.toolName === 'string' && event.toolName) {
|
|
4187
|
+
return event.toolName;
|
|
4188
|
+
}
|
|
4189
|
+
return undefined;
|
|
4190
|
+
};
|
|
4191
|
+
const shouldIncludeArguments = (event, name) => {
|
|
4192
|
+
if (!hasOwn(event, 'arguments')) {
|
|
4193
|
+
return false;
|
|
4194
|
+
}
|
|
4195
|
+
if (name === 'getWorkspaceUri') {
|
|
4196
|
+
return false;
|
|
4197
|
+
}
|
|
4198
|
+
return true;
|
|
4199
|
+
};
|
|
4200
|
+
const getPreviewEvent = event => {
|
|
4201
|
+
const name = getPreviewName(event);
|
|
4202
|
+
const previewEvent = {
|
|
4203
|
+
...(name === undefined ? {} : {
|
|
4204
|
+
name
|
|
4205
|
+
}),
|
|
4206
|
+
...(shouldIncludeArguments(event, name) ? {
|
|
4207
|
+
arguments: event.arguments
|
|
4208
|
+
} : {}),
|
|
4209
|
+
...(hasOwn(event, 'result') ? {
|
|
4210
|
+
result: event.result
|
|
4211
|
+
} : {})
|
|
4212
|
+
};
|
|
4213
|
+
if (Object.keys(previewEvent).length > 0) {
|
|
4214
|
+
return previewEvent;
|
|
4215
|
+
}
|
|
4216
|
+
return event;
|
|
4217
|
+
};
|
|
4218
|
+
|
|
4036
4219
|
const getSashNodesDom = hasSelectedEvent => {
|
|
4037
4220
|
if (!hasSelectedEvent) {
|
|
4038
4221
|
return [];
|
|
4039
4222
|
}
|
|
4040
4223
|
return [{
|
|
4041
4224
|
childCount: 1,
|
|
4042
|
-
className:
|
|
4225
|
+
className: ChatDebugViewSash,
|
|
4043
4226
|
onPointerDown: HandleSashPointerDown,
|
|
4044
4227
|
type: Div
|
|
4045
4228
|
}, {
|
|
4046
4229
|
childCount: 0,
|
|
4047
|
-
className:
|
|
4230
|
+
className: ChatDebugViewSashLine,
|
|
4048
4231
|
type: Div
|
|
4049
4232
|
}];
|
|
4050
4233
|
};
|
|
@@ -4052,7 +4235,7 @@ const getSashNodesDom = hasSelectedEvent => {
|
|
|
4052
4235
|
const getTableBodyDom = (rowNodes, eventCount) => {
|
|
4053
4236
|
return [{
|
|
4054
4237
|
childCount: eventCount === 0 ? 1 : eventCount,
|
|
4055
|
-
className:
|
|
4238
|
+
className: ChatDebugViewTableBody,
|
|
4056
4239
|
onContextMenu: HandleTableBodyContextMenu,
|
|
4057
4240
|
onPointerDown: HandleEventRowClick,
|
|
4058
4241
|
type: TBody
|
|
@@ -4062,25 +4245,25 @@ const getTableBodyDom = (rowNodes, eventCount) => {
|
|
|
4062
4245
|
const getTableHeaderDom = () => {
|
|
4063
4246
|
return [{
|
|
4064
4247
|
childCount: 1,
|
|
4065
|
-
className:
|
|
4248
|
+
className: ChatDebugViewTableHeader,
|
|
4066
4249
|
type: THead
|
|
4067
4250
|
}, {
|
|
4068
4251
|
childCount: 3,
|
|
4069
|
-
className:
|
|
4252
|
+
className: ChatDebugViewTableHeaderRow,
|
|
4070
4253
|
type: Tr
|
|
4071
4254
|
}, {
|
|
4072
4255
|
childCount: 1,
|
|
4073
|
-
className:
|
|
4256
|
+
className: ChatDebugViewHeaderCell,
|
|
4074
4257
|
scope: 'col',
|
|
4075
4258
|
type: Th
|
|
4076
4259
|
}, text('Type'), {
|
|
4077
4260
|
childCount: 1,
|
|
4078
|
-
className:
|
|
4261
|
+
className: ChatDebugViewHeaderCell,
|
|
4079
4262
|
scope: 'col',
|
|
4080
4263
|
type: Th
|
|
4081
4264
|
}, text('Duration'), {
|
|
4082
4265
|
childCount: 1,
|
|
4083
|
-
className:
|
|
4266
|
+
className: ChatDebugViewHeaderCell,
|
|
4084
4267
|
scope: 'col',
|
|
4085
4268
|
type: Th
|
|
4086
4269
|
}, text('Status')];
|
|
@@ -4089,16 +4272,20 @@ const getTableHeaderDom = () => {
|
|
|
4089
4272
|
const getTableDom = (rowNodes, eventCount) => {
|
|
4090
4273
|
return [{
|
|
4091
4274
|
childCount: 2,
|
|
4092
|
-
className:
|
|
4275
|
+
className: ChatDebugViewTable,
|
|
4093
4276
|
type: Table
|
|
4094
4277
|
}, ...getTableHeaderDom(), ...getTableBodyDom(rowNodes, eventCount)];
|
|
4095
4278
|
};
|
|
4096
4279
|
|
|
4280
|
+
const formatPercent = value => {
|
|
4281
|
+
return `${Number(value.toFixed(3))}%`;
|
|
4282
|
+
};
|
|
4283
|
+
|
|
4097
4284
|
const getBucketUnitDom = unitCount => {
|
|
4098
4285
|
if (unitCount === 0) {
|
|
4099
4286
|
return [{
|
|
4100
4287
|
childCount: 0,
|
|
4101
|
-
className:
|
|
4288
|
+
className: joinClassNames(ChatDebugViewTimelineBucketUnit, ChatDebugViewTimelineBucketUnitEmpty),
|
|
4102
4289
|
type: Div
|
|
4103
4290
|
}];
|
|
4104
4291
|
}
|
|
@@ -4106,7 +4293,7 @@ const getBucketUnitDom = unitCount => {
|
|
|
4106
4293
|
length: unitCount
|
|
4107
4294
|
}).fill({
|
|
4108
4295
|
childCount: 0,
|
|
4109
|
-
className:
|
|
4296
|
+
className: ChatDebugViewTimelineBucketUnit,
|
|
4110
4297
|
type: Div
|
|
4111
4298
|
});
|
|
4112
4299
|
};
|
|
@@ -4115,12 +4302,12 @@ const getBucketDom = bucket => {
|
|
|
4115
4302
|
const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
|
|
4116
4303
|
return [{
|
|
4117
4304
|
childCount: 2,
|
|
4118
|
-
className:
|
|
4305
|
+
className: joinClassNames(ChatDebugViewTimelineBucket, bucket.isSelected && ChatDebugViewTimelineBucketSelected),
|
|
4119
4306
|
type: Label
|
|
4120
4307
|
}, {
|
|
4121
4308
|
checked: false,
|
|
4122
4309
|
childCount: 0,
|
|
4123
|
-
className:
|
|
4310
|
+
className: ChatDebugViewTimelinePresetInput,
|
|
4124
4311
|
inputType: 'radio',
|
|
4125
4312
|
name: TimelineRangePreset,
|
|
4126
4313
|
onChange: HandleSimpleInput,
|
|
@@ -4128,11 +4315,24 @@ const getBucketDom = bucket => {
|
|
|
4128
4315
|
value: presetValue
|
|
4129
4316
|
}, {
|
|
4130
4317
|
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
4131
|
-
className:
|
|
4318
|
+
className: joinClassNames(ChatDebugViewTimelineBucketBar, bucket.isSelected && ChatDebugViewTimelineBucketBarSelected),
|
|
4132
4319
|
type: Div
|
|
4133
4320
|
}, ...getBucketUnitDom(bucket.unitCount)];
|
|
4134
4321
|
};
|
|
4135
4322
|
|
|
4323
|
+
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4324
|
+
if (!timelineSelectionActive) {
|
|
4325
|
+
return {
|
|
4326
|
+
endSeconds: timelineEndSeconds,
|
|
4327
|
+
startSeconds: timelineStartSeconds
|
|
4328
|
+
};
|
|
4329
|
+
}
|
|
4330
|
+
return {
|
|
4331
|
+
endSeconds: timelineSelectionFocusSeconds,
|
|
4332
|
+
startSeconds: timelineSelectionAnchorSeconds
|
|
4333
|
+
};
|
|
4334
|
+
};
|
|
4335
|
+
|
|
4136
4336
|
const formatTimelineSeconds = value => {
|
|
4137
4337
|
if (Number.isInteger(value)) {
|
|
4138
4338
|
return `${value}s`;
|
|
@@ -4148,21 +4348,6 @@ const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSec
|
|
|
4148
4348
|
return `Window 0s-${formatTimelineSeconds(timelineInfo.durationSeconds)} of ${formatTimelineSeconds(timelineInfo.durationSeconds)}`;
|
|
4149
4349
|
};
|
|
4150
4350
|
|
|
4151
|
-
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4152
|
-
if (!timelineSelectionActive) {
|
|
4153
|
-
return {
|
|
4154
|
-
endSeconds: timelineEndSeconds,
|
|
4155
|
-
startSeconds: timelineStartSeconds
|
|
4156
|
-
};
|
|
4157
|
-
}
|
|
4158
|
-
return {
|
|
4159
|
-
endSeconds: timelineSelectionFocusSeconds,
|
|
4160
|
-
startSeconds: timelineSelectionAnchorSeconds
|
|
4161
|
-
};
|
|
4162
|
-
};
|
|
4163
|
-
const formatPercent = value => {
|
|
4164
|
-
return `${Number(value.toFixed(3))}%`;
|
|
4165
|
-
};
|
|
4166
4351
|
const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '') => {
|
|
4167
4352
|
const effectiveRange = getEffectiveTimelineRange(timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4168
4353
|
const timelineInfo = getTimelineInfo(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds);
|
|
@@ -4171,45 +4356,45 @@ const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSecon
|
|
|
4171
4356
|
}
|
|
4172
4357
|
const selectionNodes = timelineInfo.hasSelection && timelineInfo.selectionStartPercent !== null && timelineInfo.selectionEndPercent !== null ? [{
|
|
4173
4358
|
childCount: 0,
|
|
4174
|
-
className:
|
|
4359
|
+
className: ChatDebugViewTimelineSelectionRange,
|
|
4175
4360
|
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};width:${formatPercent(timelineInfo.selectionEndPercent - timelineInfo.selectionStartPercent)};`,
|
|
4176
4361
|
type: Div
|
|
4177
4362
|
}, {
|
|
4178
4363
|
childCount: 0,
|
|
4179
|
-
className:
|
|
4364
|
+
className: joinClassNames(ChatDebugViewTimelineSelectionMarker, ChatDebugViewTimelineSelectionMarkerStart),
|
|
4180
4365
|
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};`,
|
|
4181
4366
|
type: Div
|
|
4182
4367
|
}, {
|
|
4183
4368
|
childCount: 0,
|
|
4184
|
-
className:
|
|
4369
|
+
className: joinClassNames(ChatDebugViewTimelineSelectionMarker, ChatDebugViewTimelineSelectionMarkerEnd),
|
|
4185
4370
|
style: `left:${formatPercent(timelineInfo.selectionEndPercent)};`,
|
|
4186
4371
|
type: Div
|
|
4187
4372
|
}] : [];
|
|
4188
4373
|
return [{
|
|
4189
4374
|
childCount: 2,
|
|
4190
|
-
className:
|
|
4375
|
+
className: ChatDebugViewTimeline,
|
|
4191
4376
|
type: Div
|
|
4192
4377
|
}, {
|
|
4193
4378
|
childCount: 1,
|
|
4194
|
-
className:
|
|
4379
|
+
className: ChatDebugViewTimelineTop,
|
|
4195
4380
|
type: Div
|
|
4196
4381
|
}, {
|
|
4197
4382
|
childCount: 1,
|
|
4198
|
-
className:
|
|
4383
|
+
className: ChatDebugViewTimelineSummary,
|
|
4199
4384
|
type: Div
|
|
4200
4385
|
}, text(getTimelineSummary(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds)), {
|
|
4201
4386
|
childCount: 2,
|
|
4202
|
-
className:
|
|
4387
|
+
className: ChatDebugViewTimelineInteractive,
|
|
4203
4388
|
onDoubleClick: HandleTimelineDoubleClick,
|
|
4204
4389
|
onPointerDown: HandleTimelinePointerDown,
|
|
4205
4390
|
type: Div
|
|
4206
4391
|
}, {
|
|
4207
4392
|
childCount: timelineInfo.buckets.length,
|
|
4208
|
-
className:
|
|
4393
|
+
className: ChatDebugViewTimelineBuckets,
|
|
4209
4394
|
type: Div
|
|
4210
4395
|
}, ...timelineInfo.buckets.flatMap(getBucketDom), {
|
|
4211
4396
|
childCount: selectionNodes.length,
|
|
4212
|
-
className:
|
|
4397
|
+
className: ChatDebugViewTimelineSelectionOverlay,
|
|
4213
4398
|
type: Div
|
|
4214
4399
|
}, ...selectionNodes];
|
|
4215
4400
|
};
|
|
@@ -4217,25 +4402,29 @@ const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSecon
|
|
|
4217
4402
|
const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = 'No events have been found', timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
4218
4403
|
const rowNodes = getDevtoolsRows(events, selectedEventIndex);
|
|
4219
4404
|
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4220
|
-
const
|
|
4221
|
-
const
|
|
4405
|
+
const previewEventNodes = selectedEvent ? getEventNode(getPreviewEvent(selectedEvent)) : [];
|
|
4406
|
+
const responseEventNodes = selectedEvent ? getEventNode(selectedEvent) : [];
|
|
4407
|
+
const hasSelectedEvent = responseEventNodes.length > 0;
|
|
4222
4408
|
const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableDom(rowNodes, events.length);
|
|
4223
4409
|
const eventsClassName = getEventsClassName(hasSelectedEvent);
|
|
4224
|
-
const detailsNodes = getDetailsDom(
|
|
4410
|
+
const detailsNodes = getDetailsDom(previewEventNodes, responseEventNodes, selectedEvent, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response);
|
|
4225
4411
|
const sashNodes = getSashNodesDom(hasSelectedEvent);
|
|
4226
4412
|
const splitChildCount = hasSelectedEvent ? 3 : 1;
|
|
4227
4413
|
const mainChildCount = 1 + (timelineNodes.length > 0 ? 1 : 0);
|
|
4228
4414
|
return [{
|
|
4229
4415
|
childCount: mainChildCount,
|
|
4230
|
-
className:
|
|
4416
|
+
className: ChatDebugViewDevtoolsMain,
|
|
4231
4417
|
type: Div
|
|
4232
4418
|
}, ...timelineNodes, {
|
|
4233
4419
|
childCount: splitChildCount,
|
|
4234
|
-
className:
|
|
4420
|
+
className: ChatDebugViewDevtoolsSplit,
|
|
4235
4421
|
type: Div
|
|
4236
4422
|
}, {
|
|
4237
4423
|
childCount: 1,
|
|
4238
4424
|
className: eventsClassName,
|
|
4425
|
+
onKeyDown: HandleTableKeyDown,
|
|
4426
|
+
role: 'application',
|
|
4427
|
+
tabIndex: 0,
|
|
4239
4428
|
type: Div
|
|
4240
4429
|
}, ...tableNodes, ...sashNodes, ...detailsNodes];
|
|
4241
4430
|
};
|
|
@@ -4243,11 +4432,13 @@ const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvent
|
|
|
4243
4432
|
const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
4244
4433
|
return [{
|
|
4245
4434
|
childCount: eventNodes.length === 0 ? 1 : eventNodes.length,
|
|
4246
|
-
className:
|
|
4435
|
+
className: ChatDebugViewEvents,
|
|
4436
|
+
role: 'application',
|
|
4437
|
+
tabIndex: 0,
|
|
4247
4438
|
type: Div
|
|
4248
4439
|
}, ...(eventNodes.length === 0 ? [{
|
|
4249
4440
|
childCount: 1,
|
|
4250
|
-
className: errorMessage ?
|
|
4441
|
+
className: errorMessage ? ChatDebugViewError : ChatDebugViewEmpty,
|
|
4251
4442
|
type: Div
|
|
4252
4443
|
}, text(errorMessage || emptyMessage)] : eventNodes)];
|
|
4253
4444
|
};
|
|
@@ -4255,18 +4446,18 @@ const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
|
4255
4446
|
const getQuickFilterNodes = (eventCategoryFilter, eventCategoryFilterOptions) => {
|
|
4256
4447
|
return [{
|
|
4257
4448
|
childCount: eventCategoryFilterOptions.length,
|
|
4258
|
-
className:
|
|
4449
|
+
className: ChatDebugViewQuickFilters,
|
|
4259
4450
|
type: Div
|
|
4260
4451
|
}, ...eventCategoryFilterOptions.flatMap(option => {
|
|
4261
4452
|
const isSelected = option.value === eventCategoryFilter;
|
|
4262
4453
|
return [{
|
|
4263
4454
|
childCount: 2,
|
|
4264
|
-
className:
|
|
4455
|
+
className: joinClassNames(ChatDebugViewQuickFilterPill, isSelected && ChatDebugViewQuickFilterPillSelected),
|
|
4265
4456
|
type: Label
|
|
4266
4457
|
}, {
|
|
4267
4458
|
checked: isSelected,
|
|
4268
4459
|
childCount: 0,
|
|
4269
|
-
className:
|
|
4460
|
+
className: ChatDebugViewQuickFilterInput,
|
|
4270
4461
|
inputType: 'radio',
|
|
4271
4462
|
name: EventCategoryFilter,
|
|
4272
4463
|
onChange: HandleInput,
|
|
@@ -4318,7 +4509,7 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eve
|
|
|
4318
4509
|
const rootChildCount = 2;
|
|
4319
4510
|
return [{
|
|
4320
4511
|
childCount: rootChildCount,
|
|
4321
|
-
className:
|
|
4512
|
+
className: joinClassNames(ChatDebugView, useDevtoolsLayout && ChatDebugViewDevtools),
|
|
4322
4513
|
type: Div
|
|
4323
4514
|
}, ...debugViewTopDom, ...contentNodes];
|
|
4324
4515
|
};
|
|
@@ -4385,7 +4576,7 @@ const render2 = (uid, diffResult) => {
|
|
|
4385
4576
|
const renderEventListeners = () => {
|
|
4386
4577
|
return [{
|
|
4387
4578
|
name: HandleEventRowClick,
|
|
4388
|
-
params: ['handleEventRowClick', 'event.target.dataset.index']
|
|
4579
|
+
params: ['handleEventRowClick', 'event.target.dataset.index', 'event.button']
|
|
4389
4580
|
}, {
|
|
4390
4581
|
name: HandleTableBodyContextMenu,
|
|
4391
4582
|
params: ['handleTableBodyContextMenu'],
|
|
@@ -4537,7 +4728,9 @@ const commandMap = {
|
|
|
4537
4728
|
'ChatDebug.create': create,
|
|
4538
4729
|
'ChatDebug.diff2': diff2,
|
|
4539
4730
|
'ChatDebug.getCommandIds': getCommandIds,
|
|
4731
|
+
'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
|
|
4540
4732
|
'ChatDebug.handleEventRowClick': wrapCommand(handleEventRowClick),
|
|
4733
|
+
'ChatDebug.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
|
|
4541
4734
|
'ChatDebug.handleInput': wrapCommand(handleInput),
|
|
4542
4735
|
'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
|
|
4543
4736
|
'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
|