@lvce-editor/chat-debug-view 6.0.0 → 7.1.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.
@@ -54,6 +54,49 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const Object$1 = 1;
64
+ const Number$1 = 2;
65
+ const Array$1 = 3;
66
+ const String$1 = 4;
67
+ const Boolean$1 = 5;
68
+ const Function = 6;
69
+ const Null = 7;
70
+ const Unknown = 8;
71
+ const getType = value => {
72
+ switch (typeof value) {
73
+ case 'number':
74
+ return Number$1;
75
+ case 'function':
76
+ return Function;
77
+ case 'string':
78
+ return String$1;
79
+ case 'object':
80
+ if (value === null) {
81
+ return Null;
82
+ }
83
+ if (Array.isArray(value)) {
84
+ return Array$1;
85
+ }
86
+ return Object$1;
87
+ case 'boolean':
88
+ return Boolean$1;
89
+ default:
90
+ return Unknown;
91
+ }
92
+ };
93
+ const number = value => {
94
+ const type = getType(value);
95
+ if (type !== Number$1) {
96
+ throw new AssertionError('expected value to be of type number');
97
+ }
98
+ };
99
+
57
100
  const isMessagePort = value => {
58
101
  return value && value instanceof MessagePort;
59
102
  };
@@ -1074,7 +1117,7 @@ const create$2 = rpcId => {
1074
1117
  };
1075
1118
  };
1076
1119
 
1077
- const Button = 1;
1120
+ const Button$1 = 1;
1078
1121
  const Div = 4;
1079
1122
  const Input = 6;
1080
1123
  const Span = 8;
@@ -1085,10 +1128,12 @@ const Text = 12;
1085
1128
  const Th = 13;
1086
1129
  const THead = 14;
1087
1130
  const Tr = 15;
1131
+ const Section = 41;
1088
1132
  const Search = 42;
1089
1133
  const Label = 66;
1090
1134
  const Reference = 100;
1091
1135
 
1136
+ const Button = 'event.button';
1092
1137
  const ClientX = 'event.clientX';
1093
1138
  const ClientY = 'event.clientY';
1094
1139
  const TargetName = 'event.target.name';
@@ -1102,14 +1147,22 @@ const SetDom2 = 'Viewlet.setDom2';
1102
1147
  const SetPatches = 'Viewlet.setPatches';
1103
1148
 
1104
1149
  const {
1105
- invoke,
1150
+ invoke: invoke$1,
1106
1151
  set: set$2
1107
1152
  } = create$2(ChatStorageWorker);
1108
1153
 
1109
1154
  const {
1155
+ invoke,
1110
1156
  invokeAndTransfer,
1111
1157
  set: set$1
1112
1158
  } = create$2(RendererWorker);
1159
+ const showContextMenu2 = async (uid, menuId, x, y, args) => {
1160
+ number(uid);
1161
+ number(menuId);
1162
+ number(x);
1163
+ number(y);
1164
+ await invoke('ContextMenu.show2', uid, menuId, x, y, args);
1165
+ };
1113
1166
  const sendMessagePortToChatStorageWorker$1 = async port => {
1114
1167
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatStorageWorker', port, 'HandleMessagePort.handleMessagePort');
1115
1168
  };
@@ -1234,6 +1287,41 @@ const terminate = () => {
1234
1287
  globalThis.close();
1235
1288
  };
1236
1289
 
1290
+ const appendEvent = async event => {
1291
+ return invoke$1('ChatStorage.appendEvent', event);
1292
+ };
1293
+ const listChatViewEvents$1 = async sessionId => {
1294
+ return invoke$1('ChatStorage.listChatViewEvents', sessionId);
1295
+ };
1296
+ const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1297
+ return invoke$1('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1298
+ };
1299
+
1300
+ const appendStoredEventForTestDependencies = {
1301
+ appendEvent: appendEvent
1302
+ };
1303
+ const appendStoredEventForTest = async (state, event) => {
1304
+ await appendStoredEventForTestDependencies.appendEvent(event);
1305
+ return state;
1306
+ };
1307
+
1308
+ const Response = 'response';
1309
+ const Preview = 'preview';
1310
+ const Timing = 'timing';
1311
+ const detailTabs = [Preview, Response, Timing];
1312
+ const isDetailTab = value => {
1313
+ return value === Response || value === Preview || value === Timing;
1314
+ };
1315
+ const getDetailTabLabel = value => {
1316
+ if (value === Preview) {
1317
+ return 'Preview';
1318
+ }
1319
+ if (value === Timing) {
1320
+ return 'Timing';
1321
+ }
1322
+ return 'Response';
1323
+ };
1324
+
1237
1325
  const createEventCategoryFilterOptions = () => {
1238
1326
  return [{
1239
1327
  label: 'All',
@@ -1293,6 +1381,34 @@ const parseFilterValue = filterValue => {
1293
1381
  };
1294
1382
  };
1295
1383
 
1384
+ const validEventCategoryFilters = new Set([All, Network, Stream, Tools, Ui]);
1385
+ const isSavedState = value => {
1386
+ return typeof value === 'object' && value !== null;
1387
+ };
1388
+ const getRestoredEventCategoryFilter = (savedState, currentEventCategoryFilter) => {
1389
+ if (typeof savedState.eventCategoryFilter === 'string' && validEventCategoryFilters.has(savedState.eventCategoryFilter)) {
1390
+ return savedState.eventCategoryFilter;
1391
+ }
1392
+ if (typeof savedState.filterValue === 'string') {
1393
+ return parseFilterValue(savedState.filterValue).eventCategoryFilter;
1394
+ }
1395
+ return currentEventCategoryFilter;
1396
+ };
1397
+ const restoreSavedState = (state, savedState) => {
1398
+ if (!isSavedState(savedState)) {
1399
+ return state;
1400
+ }
1401
+ return {
1402
+ ...state,
1403
+ eventCategoryFilter: getRestoredEventCategoryFilter(savedState, state.eventCategoryFilter),
1404
+ filterValue: typeof savedState.filterValue === 'string' ? savedState.filterValue : state.filterValue,
1405
+ selectedDetailTab: typeof savedState.selectedDetailTab === 'string' && isDetailTab(savedState.selectedDetailTab) ? savedState.selectedDetailTab : state.selectedDetailTab,
1406
+ selectedEventId: typeof savedState.selectedEventId === 'number' || savedState.selectedEventId === null ? savedState.selectedEventId : state.selectedEventId,
1407
+ timelineEndSeconds: typeof savedState.timelineEndSeconds === 'string' ? savedState.timelineEndSeconds : state.timelineEndSeconds,
1408
+ timelineStartSeconds: typeof savedState.timelineStartSeconds === 'string' ? savedState.timelineStartSeconds : state.timelineStartSeconds
1409
+ };
1410
+ };
1411
+
1296
1412
  const {
1297
1413
  get,
1298
1414
  getCommandIds,
@@ -1302,23 +1418,6 @@ const {
1302
1418
  wrapGetter
1303
1419
  } = create$1();
1304
1420
 
1305
- const Response = 'response';
1306
- const Preview = 'preview';
1307
- const Timing = 'timing';
1308
- const detailTabs = [Preview, Response, Timing];
1309
- const isDetailTab = value => {
1310
- return value === Response || value === Preview || value === Timing;
1311
- };
1312
- const getDetailTabLabel = value => {
1313
- if (value === Preview) {
1314
- return 'Preview';
1315
- }
1316
- if (value === Timing) {
1317
- return 'Timing';
1318
- }
1319
- return 'Response';
1320
- };
1321
-
1322
1421
  const defaultTableWidth = 480;
1323
1422
  const minTableWidth = 240;
1324
1423
  const minDetailsWidth = 280;
@@ -1384,43 +1483,19 @@ const createDefaultState = () => {
1384
1483
  };
1385
1484
  };
1386
1485
 
1387
- const validEventCategoryFilters = new Set([All, Network, Stream, Tools, Ui]);
1388
- const getRestoredEventCategoryFilter = savedState => {
1389
- if (typeof savedState.eventCategoryFilter === 'string' && validEventCategoryFilters.has(savedState.eventCategoryFilter)) {
1390
- return savedState.eventCategoryFilter;
1391
- }
1392
- if (typeof savedState.filterValue === 'string') {
1393
- return parseFilterValue(savedState.filterValue).eventCategoryFilter;
1394
- }
1395
- return All;
1396
- };
1397
1486
  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 = {}) => {
1398
1487
  const defaultState = createDefaultState();
1399
- const {
1400
- filterValue,
1401
- selectedEventId,
1402
- tableWidth,
1403
- timelineEndSeconds,
1404
- timelineStartSeconds
1405
- } = savedState;
1406
- const restoredEventCategoryFilter = getRestoredEventCategoryFilter(savedState);
1407
1488
  const state = {
1408
- ...defaultState,
1489
+ ...restoreSavedState(defaultState, savedState),
1409
1490
  assetDir,
1410
1491
  databaseName,
1411
1492
  dataBaseVersion,
1412
- eventCategoryFilter: restoredEventCategoryFilter,
1413
1493
  eventStoreName,
1414
- filterValue: filterValue ?? defaultState.filterValue,
1415
1494
  height,
1416
1495
  initial: true,
1417
1496
  platform,
1418
- selectedEventId: selectedEventId ?? defaultState.selectedEventId,
1419
1497
  sessionId,
1420
1498
  sessionIdIndexName,
1421
- tableWidth: tableWidth ?? defaultState.tableWidth,
1422
- timelineEndSeconds: timelineEndSeconds ?? defaultState.timelineEndSeconds,
1423
- timelineStartSeconds: timelineStartSeconds ?? defaultState.timelineStartSeconds,
1424
1499
  uid,
1425
1500
  uri,
1426
1501
  width,
@@ -1449,27 +1524,28 @@ const diff2 = uid => {
1449
1524
  return diff(oldState, newState);
1450
1525
  };
1451
1526
 
1452
- const handleCloseDetails = state => {
1453
- return {
1454
- ...state,
1455
- selectedEvent: null,
1456
- selectedEventId: null,
1457
- selectedEventIndex: null
1458
- };
1527
+ const getMenuIds = () => {
1528
+ return [555, 556, 557];
1459
1529
  };
1460
1530
 
1461
- const handleDetailsContextMenu = state => {
1462
- return state;
1531
+ const getErrorMessage = error => {
1532
+ if (error instanceof Error) {
1533
+ return error.message;
1534
+ }
1535
+ if (typeof error === 'string') {
1536
+ return error;
1537
+ }
1538
+ if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
1539
+ return error.message;
1540
+ }
1541
+ return undefined;
1463
1542
  };
1464
-
1465
- const handleDetailTab = (state, value) => {
1466
- if (!isDetailTab(value)) {
1467
- return state;
1543
+ const getFailedToLoadMessage = (sessionId, error) => {
1544
+ const errorMessage = getErrorMessage(error);
1545
+ if (errorMessage) {
1546
+ return `Failed to load chat debug session "${sessionId}": ${errorMessage}`;
1468
1547
  }
1469
- return {
1470
- ...state,
1471
- selectedDetailTab: value
1472
- };
1548
+ return `Failed to load chat debug session "${sessionId}". Please try again.`;
1473
1549
  };
1474
1550
 
1475
1551
  const hasMatchingToolName = (startedEvent, finishedEvent) => {
@@ -1639,6 +1715,24 @@ const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEv
1639
1715
  return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
1640
1716
  };
1641
1717
 
1718
+ const ParseChatDebugUriErrorCode = {
1719
+ InvalidSessionId: 'invalid-session-id',
1720
+ InvalidUriEncoding: 'invalid-uri-encoding',
1721
+ InvalidUriFormat: 'invalid-uri-format',
1722
+ MissingUri: 'missing-uri'
1723
+ };
1724
+
1725
+ const getInvalidUriMessage = (uri, code) => {
1726
+ if (code === ParseChatDebugUriErrorCode.MissingUri) {
1727
+ return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
1728
+ }
1729
+ return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
1730
+ };
1731
+
1732
+ const getSessionNotFoundMessage = sessionId => {
1733
+ return `No chat session found for sessionId "${sessionId}".`;
1734
+ };
1735
+
1642
1736
  const toTimeNumber = value => {
1643
1737
  if (typeof value === 'number' && Number.isFinite(value)) {
1644
1738
  return value;
@@ -1790,74 +1884,18 @@ const getTimelineInfo = (events, startValue, endValue) => {
1790
1884
  };
1791
1885
  };
1792
1886
 
1793
- const getCurrentEvents$3 = state => {
1794
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1795
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1796
- };
1797
- const getEventIndexByStableId$1 = (events, event) => {
1798
- const stableEventId = getStableEventId(event);
1799
- return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
1800
- };
1801
- const getSelectedEventIndex$1 = state => {
1802
- const {
1803
- selectedEventIndex
1804
- } = state;
1805
- if (selectedEventIndex === null) {
1806
- return null;
1807
- }
1808
- const filteredEvents = getCurrentEvents$3(state);
1809
- const selectedEvent = filteredEvents[selectedEventIndex];
1810
- if (!selectedEvent) {
1811
- return null;
1812
- }
1813
- const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
1814
- if (newIndex === -1) {
1815
- return null;
1816
- }
1817
- return newIndex;
1887
+ const listChatViewEventsDependencies = {
1888
+ listChatViewEventsFromWorker: listChatViewEvents$1
1818
1889
  };
1819
- const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
1820
- const {
1821
- selectedEventIndex
1822
- } = oldState;
1823
- if (selectedEventIndex === null) {
1824
- return null;
1825
- }
1826
- const oldFilteredEvents = getCurrentEvents$3(oldState);
1827
- const selectedEvent = oldFilteredEvents[selectedEventIndex];
1828
- if (!selectedEvent) {
1829
- return null;
1830
- }
1831
- const newFilteredEvents = getCurrentEvents$3(newState);
1832
- const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
1833
- if (newIndex === -1) {
1834
- return null;
1890
+ const listChatViewEvents = async (sessionId, _databaseName, _dataBaseVersion, _eventStoreName, _sessionIdIndexName) => {
1891
+ try {
1892
+ return await listChatViewEventsDependencies.listChatViewEventsFromWorker(sessionId);
1893
+ } catch (error) {
1894
+ return {
1895
+ error,
1896
+ type: 'error'
1897
+ };
1835
1898
  }
1836
- return newIndex;
1837
- };
1838
- const withPreservedSelection$1 = (state, nextState) => {
1839
- const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
1840
- return {
1841
- ...nextState,
1842
- selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
1843
- selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
1844
- selectedEventIndex
1845
- };
1846
- };
1847
-
1848
- const handleEventCategoryFilter = (state, value) => {
1849
- const nextState = {
1850
- ...state,
1851
- eventCategoryFilter: value || All
1852
- };
1853
- return withPreservedSelection$1(state, nextState);
1854
- };
1855
-
1856
- const listChatViewEvents$1 = async sessionId => {
1857
- return invoke('ChatStorage.listChatViewEvents', sessionId);
1858
- };
1859
- const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1860
- return invoke('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1861
1899
  };
1862
1900
 
1863
1901
  const loadSelectedEventDependencies = {
@@ -1867,150 +1905,254 @@ const loadSelectedEvent = async (_databaseName, _dataBaseVersion, _eventStoreNam
1867
1905
  return loadSelectedEventDependencies.loadSelectedEventFromWorker(sessionId, eventId, type);
1868
1906
  };
1869
1907
 
1870
- const getCurrentEvents$2 = state => {
1871
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1872
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1873
- };
1874
- const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
1875
- const currentEvents = getCurrentEvents$2(state);
1876
- const selectedEvent = currentEvents[selectedEventIndex];
1877
- if (!selectedEvent) {
1908
+ const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
1909
+ const invalidSessionIdPattern = /[/?#]/;
1910
+ const parseChatDebugUri = uri => {
1911
+ if (!uri) {
1878
1912
  return {
1879
- ...state,
1880
- selectedEvent: null,
1881
- selectedEventId: null,
1882
- selectedEventIndex
1913
+ code: ParseChatDebugUriErrorCode.MissingUri,
1914
+ message: 'Missing URI',
1915
+ type: 'error'
1883
1916
  };
1884
1917
  }
1885
- if (typeof selectedEvent.eventId !== 'number') {
1918
+ const match = uri.match(chatDebugUriPattern);
1919
+ if (!match) {
1886
1920
  return {
1887
- ...state,
1888
- selectedEvent,
1889
- selectedEventId: null,
1890
- selectedEventIndex
1921
+ code: ParseChatDebugUriErrorCode.InvalidUriFormat,
1922
+ message: 'Invalid URI format',
1923
+ type: 'error'
1891
1924
  };
1892
1925
  }
1893
- const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
1894
- return {
1895
- ...state,
1896
- selectedEvent: selectedEventDetails ?? selectedEvent,
1897
- selectedEventId: selectedEvent.eventId,
1898
- selectedEventIndex
1899
- };
1900
- };
1901
-
1902
- const handleEventRowClickDependencies = {
1903
- loadSelectedEvent: loadSelectedEvent
1904
- };
1905
- const isPrimaryButton = button => {
1906
- return button === 0;
1907
- };
1908
- const parseSelectedEventIndex$1 = value => {
1909
- const parsed = Number.parseInt(value, 10);
1910
- if (Number.isNaN(parsed) || parsed < 0) {
1911
- return null;
1926
+ const encodedSessionId = match[1];
1927
+ let sessionId;
1928
+ try {
1929
+ sessionId = decodeURIComponent(encodedSessionId);
1930
+ } catch {
1931
+ return {
1932
+ code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
1933
+ message: 'Invalid URI encoding',
1934
+ type: 'error'
1935
+ };
1912
1936
  }
1913
- return parsed;
1937
+ if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
1938
+ return {
1939
+ code: ParseChatDebugUriErrorCode.InvalidSessionId,
1940
+ message: 'Invalid session id',
1941
+ type: 'error'
1942
+ };
1943
+ }
1944
+ return {
1945
+ sessionId,
1946
+ type: 'success'
1947
+ };
1914
1948
  };
1915
- const handleEventRowClick = async (state, value, button = 0) => {
1916
- if (!isPrimaryButton(button)) {
1917
- return state;
1949
+
1950
+ const loadEventsDependencies = {
1951
+ listChatViewEvents: listChatViewEvents,
1952
+ loadSelectedEvent: loadSelectedEvent
1953
+ };
1954
+ const getCurrentEvents$3 = state => {
1955
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1956
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1957
+ };
1958
+ const restoreSelectedEvent = async state => {
1959
+ if (state.selectedEventId === null) {
1960
+ return {
1961
+ ...state,
1962
+ selectedEvent: null,
1963
+ selectedEventIndex: null
1964
+ };
1918
1965
  }
1919
- const selectedEventIndex = parseSelectedEventIndex$1(value);
1920
- if (selectedEventIndex === null) {
1966
+ const currentEvents = getCurrentEvents$3(state);
1967
+ const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
1968
+ if (selectedEventIndex === -1) {
1969
+ return {
1970
+ ...state,
1971
+ selectedEvent: null,
1972
+ selectedEventId: null,
1973
+ selectedEventIndex: null
1974
+ };
1975
+ }
1976
+ const selectedEvent = currentEvents[selectedEventIndex];
1977
+ if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
1978
+ return {
1979
+ ...state,
1980
+ selectedEvent: null,
1981
+ selectedEventId: null,
1982
+ selectedEventIndex: null
1983
+ };
1984
+ }
1985
+ const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
1986
+ return {
1987
+ ...state,
1988
+ selectedEvent: selectedEventDetails,
1989
+ selectedEventId: selectedEvent.eventId,
1990
+ selectedEventIndex
1991
+ };
1992
+ };
1993
+ const getStateWithInvalidUri = state => {
1994
+ const parsed = parseChatDebugUri(state.uri);
1995
+ if (parsed.type !== 'error') {
1921
1996
  return state;
1922
1997
  }
1923
- return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
1998
+ return {
1999
+ ...state,
2000
+ errorMessage: getInvalidUriMessage(state.uri, parsed.code),
2001
+ events: [],
2002
+ initial: false,
2003
+ selectedEvent: null,
2004
+ selectedEventId: null,
2005
+ selectedEventIndex: null,
2006
+ sessionId: ''
2007
+ };
2008
+ };
2009
+ const getSessionIdFromUri = state => {
2010
+ const parsed = parseChatDebugUri(state.uri);
2011
+ if (parsed.type === 'error') {
2012
+ return undefined;
2013
+ }
2014
+ return parsed.sessionId;
2015
+ };
2016
+ const loadEventsForSessionId = async (state, sessionId) => {
2017
+ const {
2018
+ databaseName,
2019
+ dataBaseVersion,
2020
+ eventStoreName,
2021
+ sessionIdIndexName
2022
+ } = state;
2023
+ const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
2024
+ if (result.type === 'error') {
2025
+ return {
2026
+ ...state,
2027
+ errorMessage: getFailedToLoadMessage(sessionId, result.error),
2028
+ events: [],
2029
+ initial: false,
2030
+ selectedEvent: null,
2031
+ selectedEventId: null,
2032
+ selectedEventIndex: null,
2033
+ sessionId
2034
+ };
2035
+ }
2036
+ const {
2037
+ events
2038
+ } = result;
2039
+ if (events.length === 0) {
2040
+ return {
2041
+ ...state,
2042
+ errorMessage: getSessionNotFoundMessage(sessionId),
2043
+ events: [],
2044
+ initial: false,
2045
+ selectedEvent: null,
2046
+ selectedEventId: null,
2047
+ selectedEventIndex: null,
2048
+ sessionId
2049
+ };
2050
+ }
2051
+ const nextState = {
2052
+ ...state,
2053
+ errorMessage: '',
2054
+ events,
2055
+ initial: false,
2056
+ sessionId
2057
+ };
2058
+ return restoreSelectedEvent(nextState);
2059
+ };
2060
+ const loadEventsFromUri = async state => {
2061
+ const sessionId = getSessionIdFromUri(state);
2062
+ if (!sessionId) {
2063
+ return getStateWithInvalidUri(state);
2064
+ }
2065
+ return loadEventsForSessionId(state, sessionId);
2066
+ };
2067
+ const refreshEvents = async state => {
2068
+ const sessionId = state.sessionId || getSessionIdFromUri(state);
2069
+ if (!sessionId) {
2070
+ return getStateWithInvalidUri(state);
2071
+ }
2072
+ return loadEventsForSessionId(state, sessionId);
1924
2073
  };
1925
2074
 
1926
- const handleHeaderContextMenu = state => {
1927
- return state;
2075
+ const refresh = async state => {
2076
+ return refreshEvents(state);
1928
2077
  };
1929
2078
 
1930
- const getBoolean = value => {
1931
- return value === true || value === 'true' || value === 'on' || value === '1';
2079
+ const handleClickRefreshDependencies = {
2080
+ refresh: refresh
2081
+ };
2082
+ const handleClickRefresh = async state => {
2083
+ return handleClickRefreshDependencies.refresh(state);
1932
2084
  };
1933
2085
 
1934
- const Filter = 'filter';
1935
- const EventCategoryFilter = 'eventCategoryFilter';
1936
- const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
1937
- const ShowInputEvents = 'showInputEvents';
1938
- const ShowResponsePartEvents = 'showResponsePartEvents';
1939
- const UseDevtoolsLayout = 'useDevtoolsLayout';
1940
- const SelectedEventIndex = 'selectedEventIndex';
1941
- const CloseDetails = 'closeDetails';
1942
- const DetailTab = 'detailTab';
1943
- const TimelineStartSeconds = 'timelineStartSeconds';
1944
- const TimelineEndSeconds = 'timelineEndSeconds';
1945
- const TimelineRangePreset = 'timelineRangePreset';
2086
+ const handleCloseDetails = state => {
2087
+ return {
2088
+ ...state,
2089
+ selectedEvent: null,
2090
+ selectedEventId: null,
2091
+ selectedEventIndex: null
2092
+ };
2093
+ };
1946
2094
 
1947
- const getCurrentEvents$1 = state => {
1948
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1949
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2095
+ const handleDetailsContextMenu = state => {
2096
+ return state;
1950
2097
  };
1951
- const parseTimelineRangePreset$1 = value => {
1952
- if (!value) {
1953
- return {
1954
- timelineEndSeconds: '',
1955
- timelineStartSeconds: ''
1956
- };
2098
+
2099
+ const handleDetailTab = (state, value) => {
2100
+ if (!isDetailTab(value)) {
2101
+ return state;
1957
2102
  }
1958
- const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
1959
2103
  return {
1960
- timelineEndSeconds,
1961
- timelineStartSeconds
2104
+ ...state,
2105
+ selectedDetailTab: value
1962
2106
  };
1963
2107
  };
1964
- const getEventIndexByStableId = (events, event) => {
2108
+
2109
+ const getCurrentEvents$2 = state => {
2110
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2111
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2112
+ };
2113
+ const getEventIndexByStableId$1 = (events, event) => {
1965
2114
  const stableEventId = getStableEventId(event);
1966
2115
  return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
1967
2116
  };
1968
- const getSelectedEventIndex = state => {
2117
+ const getSelectedEventIndex$1 = state => {
1969
2118
  const {
1970
2119
  selectedEventIndex
1971
2120
  } = state;
1972
2121
  if (selectedEventIndex === null) {
1973
2122
  return null;
1974
2123
  }
1975
- const filteredEvents = getCurrentEvents$1(state);
2124
+ const filteredEvents = getCurrentEvents$2(state);
1976
2125
  const selectedEvent = filteredEvents[selectedEventIndex];
1977
2126
  if (!selectedEvent) {
1978
2127
  return null;
1979
2128
  }
1980
- const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
2129
+ const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
1981
2130
  if (newIndex === -1) {
1982
2131
  return null;
1983
2132
  }
1984
2133
  return newIndex;
1985
2134
  };
1986
- const getPreservedSelectedEventIndex = (oldState, newState) => {
2135
+ const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
1987
2136
  const {
1988
2137
  selectedEventIndex
1989
2138
  } = oldState;
1990
2139
  if (selectedEventIndex === null) {
1991
2140
  return null;
1992
2141
  }
1993
- const oldFilteredEvents = getCurrentEvents$1(oldState);
2142
+ const oldFilteredEvents = getCurrentEvents$2(oldState);
1994
2143
  const selectedEvent = oldFilteredEvents[selectedEventIndex];
1995
2144
  if (!selectedEvent) {
1996
2145
  return null;
1997
2146
  }
1998
- const newFilteredEvents = getCurrentEvents$1(newState);
1999
- const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
2147
+ const newFilteredEvents = getCurrentEvents$2(newState);
2148
+ const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
2000
2149
  if (newIndex === -1) {
2001
2150
  return null;
2002
2151
  }
2003
2152
  return newIndex;
2004
2153
  };
2005
- const parseSelectedEventIndex = value => {
2006
- const parsed = Number.parseInt(value, 10);
2007
- if (Number.isNaN(parsed) || parsed < 0) {
2008
- return null;
2009
- }
2010
- return parsed;
2011
- };
2012
- const withPreservedSelection = (state, nextState) => {
2013
- const selectedEventIndex = getPreservedSelectedEventIndex(state, nextState);
2154
+ const withPreservedSelection$1 = (state, nextState) => {
2155
+ const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
2014
2156
  return {
2015
2157
  ...nextState,
2016
2158
  selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
@@ -2018,18 +2160,179 @@ const withPreservedSelection = (state, nextState) => {
2018
2160
  selectedEventIndex
2019
2161
  };
2020
2162
  };
2021
- const handleInput = (state, name, value, checked) => {
2022
- if (name === Filter) {
2023
- const nextState = {
2163
+
2164
+ const handleEventCategoryFilter = (state, value) => {
2165
+ const nextState = {
2166
+ ...state,
2167
+ eventCategoryFilter: value || All
2168
+ };
2169
+ return withPreservedSelection$1(state, nextState);
2170
+ };
2171
+
2172
+ const getCurrentEvents$1 = state => {
2173
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2174
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2175
+ };
2176
+ const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
2177
+ const currentEvents = getCurrentEvents$1(state);
2178
+ const selectedEvent = currentEvents[selectedEventIndex];
2179
+ if (!selectedEvent) {
2180
+ return {
2024
2181
  ...state,
2025
- filterValue: value
2182
+ selectedEvent: null,
2183
+ selectedEventId: null,
2184
+ selectedEventIndex
2026
2185
  };
2027
- return withPreservedSelection(state, nextState);
2028
2186
  }
2029
- if (name === EventCategoryFilter) {
2030
- const nextState = {
2187
+ if (typeof selectedEvent.eventId !== 'number') {
2188
+ return {
2031
2189
  ...state,
2032
- eventCategoryFilter: value || All
2190
+ selectedEvent,
2191
+ selectedEventId: null,
2192
+ selectedEventIndex
2193
+ };
2194
+ }
2195
+ const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2196
+ return {
2197
+ ...state,
2198
+ selectedEvent: selectedEventDetails ?? selectedEvent,
2199
+ selectedEventId: selectedEvent.eventId,
2200
+ selectedEventIndex
2201
+ };
2202
+ };
2203
+
2204
+ const handleEventRowClickDependencies = {
2205
+ loadSelectedEvent: loadSelectedEvent
2206
+ };
2207
+ const isPrimaryButton = button => {
2208
+ return button === 0;
2209
+ };
2210
+ const parseSelectedEventIndex$1 = value => {
2211
+ const parsed = Number.parseInt(value, 10);
2212
+ if (Number.isNaN(parsed) || parsed < 0) {
2213
+ return null;
2214
+ }
2215
+ return parsed;
2216
+ };
2217
+ const handleEventRowClick = async (state, value, button = 0) => {
2218
+ if (!isPrimaryButton(button)) {
2219
+ return state;
2220
+ }
2221
+ const selectedEventIndex = parseSelectedEventIndex$1(value);
2222
+ if (selectedEventIndex === null) {
2223
+ return state;
2224
+ }
2225
+ return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
2226
+ };
2227
+
2228
+ const handleHeaderContextMenu = state => {
2229
+ return state;
2230
+ };
2231
+
2232
+ const getBoolean = value => {
2233
+ return value === true || value === 'true' || value === 'on' || value === '1';
2234
+ };
2235
+
2236
+ const Filter = 'filter';
2237
+ const EventCategoryFilter = 'eventCategoryFilter';
2238
+ const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
2239
+ const ShowInputEvents = 'showInputEvents';
2240
+ const ShowResponsePartEvents = 'showResponsePartEvents';
2241
+ const UseDevtoolsLayout = 'useDevtoolsLayout';
2242
+ const SelectedEventIndex = 'selectedEventIndex';
2243
+ const CloseDetails = 'closeDetails';
2244
+ const DetailTab = 'detailTab';
2245
+ const TimelineStartSeconds = 'timelineStartSeconds';
2246
+ const TimelineEndSeconds = 'timelineEndSeconds';
2247
+ const TimelineRangePreset = 'timelineRangePreset';
2248
+ const Refresh = 'refresh';
2249
+
2250
+ const getCurrentEvents = state => {
2251
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2252
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2253
+ };
2254
+ const parseTimelineRangePreset$1 = value => {
2255
+ if (!value) {
2256
+ return {
2257
+ timelineEndSeconds: '',
2258
+ timelineStartSeconds: ''
2259
+ };
2260
+ }
2261
+ const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
2262
+ return {
2263
+ timelineEndSeconds,
2264
+ timelineStartSeconds
2265
+ };
2266
+ };
2267
+ const getEventIndexByStableId = (events, event) => {
2268
+ const stableEventId = getStableEventId(event);
2269
+ return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
2270
+ };
2271
+ const getSelectedEventIndex = state => {
2272
+ const {
2273
+ selectedEventIndex
2274
+ } = state;
2275
+ if (selectedEventIndex === null) {
2276
+ return null;
2277
+ }
2278
+ const filteredEvents = getCurrentEvents(state);
2279
+ const selectedEvent = filteredEvents[selectedEventIndex];
2280
+ if (!selectedEvent) {
2281
+ return null;
2282
+ }
2283
+ const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
2284
+ if (newIndex === -1) {
2285
+ return null;
2286
+ }
2287
+ return newIndex;
2288
+ };
2289
+ const getPreservedSelectedEventIndex = (oldState, newState) => {
2290
+ const {
2291
+ selectedEventIndex
2292
+ } = oldState;
2293
+ if (selectedEventIndex === null) {
2294
+ return null;
2295
+ }
2296
+ const oldFilteredEvents = getCurrentEvents(oldState);
2297
+ const selectedEvent = oldFilteredEvents[selectedEventIndex];
2298
+ if (!selectedEvent) {
2299
+ return null;
2300
+ }
2301
+ const newFilteredEvents = getCurrentEvents(newState);
2302
+ const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
2303
+ if (newIndex === -1) {
2304
+ return null;
2305
+ }
2306
+ return newIndex;
2307
+ };
2308
+ const parseSelectedEventIndex = value => {
2309
+ const parsed = Number.parseInt(value, 10);
2310
+ if (Number.isNaN(parsed) || parsed < 0) {
2311
+ return null;
2312
+ }
2313
+ return parsed;
2314
+ };
2315
+ const withPreservedSelection = (state, nextState) => {
2316
+ const selectedEventIndex = getPreservedSelectedEventIndex(state, nextState);
2317
+ return {
2318
+ ...nextState,
2319
+ selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
2320
+ selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
2321
+ selectedEventIndex
2322
+ };
2323
+ };
2324
+ const handleInput = (state, name, value, checked) => {
2325
+ if (name === Filter) {
2326
+ const nextState = {
2327
+ ...state,
2328
+ filterValue: value
2329
+ };
2330
+ return withPreservedSelection(state, nextState);
2331
+ }
2332
+ if (name === EventCategoryFilter) {
2333
+ const nextState = {
2334
+ ...state,
2335
+ eventCategoryFilter: value || All
2033
2336
  };
2034
2337
  return withPreservedSelection(state, nextState);
2035
2338
  }
@@ -2130,7 +2433,44 @@ const handleSashPointerUp = (state, eventX, eventY) => {
2130
2433
  return state;
2131
2434
  };
2132
2435
 
2133
- const handleTableBodyContextMenu = state => {
2436
+ const devtoolsRootGap = 4;
2437
+ const devtoolsTopHeight = 28;
2438
+ const devtoolsTimelineHeight = 88;
2439
+ const devtoolsTableHeaderHeight = 24;
2440
+ const devtoolsTableRowHeight = 24;
2441
+ const MenuChatDebugTableBody = 2190;
2442
+ const getTableBodyY = (state, hasTimeline) => {
2443
+ return state.y + viewPadding + devtoolsTopHeight + devtoolsRootGap + (hasTimeline ? devtoolsTimelineHeight : 0) + devtoolsTableHeaderHeight;
2444
+ };
2445
+ const getTableBodyEventIndex = (state, eventX, eventY) => {
2446
+ if (!state.useDevtoolsLayout) {
2447
+ return -1;
2448
+ }
2449
+ const currentEvents = getCurrentEvents$1(state);
2450
+ if (currentEvents.length === 0) {
2451
+ return -1;
2452
+ }
2453
+ const tableX = state.x + leftPadding;
2454
+ const tableWidth = clampTableWidth(state.width, state.tableWidth);
2455
+ const hasTimeline = currentEvents.length > 0;
2456
+ const tableBodyY = getTableBodyY(state, hasTimeline);
2457
+ const relativeX = eventX - tableX;
2458
+ const relativeY = eventY - tableBodyY;
2459
+ if (relativeX < 0 || relativeX >= tableWidth || relativeY < 0) {
2460
+ return -1;
2461
+ }
2462
+ const eventIndex = Math.floor(relativeY / devtoolsTableRowHeight);
2463
+ if (eventIndex < 0 || eventIndex >= currentEvents.length) {
2464
+ return -1;
2465
+ }
2466
+ return eventIndex;
2467
+ };
2468
+ const handleTableBodyContextMenu = async (state, eventX, eventY) => {
2469
+ const eventIndex = getTableBodyEventIndex(state, eventX, eventY);
2470
+ await showContextMenu2(state.uid, MenuChatDebugTableBody, eventX, eventY, {
2471
+ eventIndex,
2472
+ menuId: MenuChatDebugTableBody
2473
+ });
2134
2474
  return state;
2135
2475
  };
2136
2476
 
@@ -2246,1023 +2586,143 @@ const handleTimelinePointerMove = (state, eventX) => {
2246
2586
  const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2247
2587
  if (seconds === undefined) {
2248
2588
  return state;
2249
- }
2250
- return {
2251
- ...state,
2252
- timelineSelectionFocusSeconds: seconds
2253
- };
2254
- };
2255
-
2256
- const handleTimelinePointerUp = (state, eventX) => {
2257
- if (!state.timelineSelectionActive) {
2258
- return state;
2259
- }
2260
- const timelineEvents = getTimelineEvents(state);
2261
- const timelineLeft = getTimelineLeft(state);
2262
- const timelineWidth = getTimelineWidth(state);
2263
- const clientX = state.x + eventX;
2264
- const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2265
- if (focusSeconds === undefined) {
2266
- return clearTimelineSelectionState(state);
2267
- }
2268
- const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
2269
- const focus = Number.parseFloat(focusSeconds);
2270
- const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
2271
- const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
2272
- const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
2273
- return clearTimelineSelectionState(nextState);
2274
- };
2275
-
2276
- const handleUseDevtoolsLayout = (state, checked) => {
2277
- const useDevtoolsLayout = getBoolean(checked);
2278
- const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
2279
- return {
2280
- ...state,
2281
- selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
2282
- selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
2283
- selectedEventIndex,
2284
- useDevtoolsLayout
2285
- };
2286
- };
2287
-
2288
- const handleShowEventStreamFinishedEvents = (state, checked) => {
2289
- const nextState = {
2290
- ...state,
2291
- showEventStreamFinishedEvents: getBoolean(checked)
2292
- };
2293
- return withPreservedSelection$1(state, nextState);
2294
- };
2295
- const handleShowInputEvents = (state, checked) => {
2296
- const nextState = {
2297
- ...state,
2298
- showInputEvents: getBoolean(checked)
2299
- };
2300
- return withPreservedSelection$1(state, nextState);
2301
- };
2302
- const handleShowResponsePartEvents = (state, checked) => {
2303
- const nextState = {
2304
- ...state,
2305
- showResponsePartEvents: getBoolean(checked)
2306
- };
2307
- return withPreservedSelection$1(state, nextState);
2308
- };
2309
-
2310
- const getErrorMessage = error => {
2311
- if (error instanceof Error) {
2312
- return error.message;
2313
- }
2314
- if (typeof error === 'string') {
2315
- return error;
2316
- }
2317
- if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
2318
- return error.message;
2319
- }
2320
- return undefined;
2321
- };
2322
- const getFailedToLoadMessage = (sessionId, error) => {
2323
- const errorMessage = getErrorMessage(error);
2324
- if (errorMessage) {
2325
- return `Failed to load chat debug session "${sessionId}": ${errorMessage}`;
2326
- }
2327
- return `Failed to load chat debug session "${sessionId}". Please try again.`;
2328
- };
2329
-
2330
- const ParseChatDebugUriErrorCode = {
2331
- InvalidSessionId: 'invalid-session-id',
2332
- InvalidUriEncoding: 'invalid-uri-encoding',
2333
- InvalidUriFormat: 'invalid-uri-format',
2334
- MissingUri: 'missing-uri'
2335
- };
2336
-
2337
- const getInvalidUriMessage = (uri, code) => {
2338
- if (code === ParseChatDebugUriErrorCode.MissingUri) {
2339
- return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
2340
- }
2341
- return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
2342
- };
2343
-
2344
- const getSessionNotFoundMessage = sessionId => {
2345
- return `No chat session found for sessionId "${sessionId}".`;
2346
- };
2347
-
2348
- const listChatViewEventsDependencies = {
2349
- listChatViewEventsFromWorker: listChatViewEvents$1
2350
- };
2351
- const listChatViewEvents = async (sessionId, _databaseName, _dataBaseVersion, _eventStoreName, _sessionIdIndexName) => {
2352
- try {
2353
- return await listChatViewEventsDependencies.listChatViewEventsFromWorker(sessionId);
2354
- } catch (error) {
2355
- return {
2356
- error,
2357
- type: 'error'
2358
- };
2359
- }
2360
- };
2361
-
2362
- const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
2363
- const invalidSessionIdPattern = /[/?#]/;
2364
- const parseChatDebugUri = uri => {
2365
- if (!uri) {
2366
- return {
2367
- code: ParseChatDebugUriErrorCode.MissingUri,
2368
- message: 'Missing URI',
2369
- type: 'error'
2370
- };
2371
- }
2372
- const match = uri.match(chatDebugUriPattern);
2373
- if (!match) {
2374
- return {
2375
- code: ParseChatDebugUriErrorCode.InvalidUriFormat,
2376
- message: 'Invalid URI format',
2377
- type: 'error'
2378
- };
2379
- }
2380
- const encodedSessionId = match[1];
2381
- let sessionId;
2382
- try {
2383
- sessionId = decodeURIComponent(encodedSessionId);
2384
- } catch {
2385
- return {
2386
- code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
2387
- message: 'Invalid URI encoding',
2388
- type: 'error'
2389
- };
2390
- }
2391
- if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
2392
- return {
2393
- code: ParseChatDebugUriErrorCode.InvalidSessionId,
2394
- message: 'Invalid session id',
2395
- type: 'error'
2396
- };
2397
- }
2398
- return {
2399
- sessionId,
2400
- type: 'success'
2401
- };
2402
- };
2403
-
2404
- const loadEventsDependencies = {
2405
- listChatViewEvents: listChatViewEvents,
2406
- loadSelectedEvent: loadSelectedEvent
2407
- };
2408
- const getCurrentEvents = state => {
2409
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2410
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2411
- };
2412
- const restoreSelectedEvent = async state => {
2413
- if (state.selectedEventId === null) {
2414
- return {
2415
- ...state,
2416
- selectedEvent: null,
2417
- selectedEventIndex: null
2418
- };
2419
- }
2420
- const currentEvents = getCurrentEvents(state);
2421
- const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
2422
- if (selectedEventIndex === -1) {
2423
- return {
2424
- ...state,
2425
- selectedEvent: null,
2426
- selectedEventId: null,
2427
- selectedEventIndex: null
2428
- };
2429
- }
2430
- const selectedEvent = currentEvents[selectedEventIndex];
2431
- if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
2432
- return {
2433
- ...state,
2434
- selectedEvent: null,
2435
- selectedEventId: null,
2436
- selectedEventIndex: null
2437
- };
2438
- }
2439
- const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2440
- return {
2441
- ...state,
2442
- selectedEvent: selectedEventDetails,
2443
- selectedEventId: selectedEvent.eventId,
2444
- selectedEventIndex
2445
- };
2446
- };
2447
- const getStateWithInvalidUri = state => {
2448
- const parsed = parseChatDebugUri(state.uri);
2449
- if (parsed.type !== 'error') {
2450
- return state;
2451
- }
2452
- return {
2453
- ...state,
2454
- errorMessage: getInvalidUriMessage(state.uri, parsed.code),
2455
- events: [],
2456
- initial: false,
2457
- selectedEvent: null,
2458
- selectedEventId: null,
2459
- selectedEventIndex: null,
2460
- sessionId: ''
2461
- };
2462
- };
2463
- const getSessionIdFromUri = state => {
2464
- const parsed = parseChatDebugUri(state.uri);
2465
- if (parsed.type === 'error') {
2466
- return undefined;
2467
- }
2468
- return parsed.sessionId;
2469
- };
2470
- const loadEventsForSessionId = async (state, sessionId) => {
2471
- const {
2472
- databaseName,
2473
- dataBaseVersion,
2474
- eventStoreName,
2475
- sessionIdIndexName
2476
- } = state;
2477
- const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
2478
- if (result.type === 'error') {
2479
- return {
2480
- ...state,
2481
- errorMessage: getFailedToLoadMessage(sessionId, result.error),
2482
- events: [],
2483
- initial: false,
2484
- selectedEvent: null,
2485
- selectedEventId: null,
2486
- selectedEventIndex: null,
2487
- sessionId
2488
- };
2489
- }
2490
- const {
2491
- events
2492
- } = result;
2493
- if (events.length === 0) {
2494
- return {
2495
- ...state,
2496
- errorMessage: getSessionNotFoundMessage(sessionId),
2497
- events: [],
2498
- initial: false,
2499
- selectedEvent: null,
2500
- selectedEventId: null,
2501
- selectedEventIndex: null,
2502
- sessionId
2503
- };
2504
- }
2505
- const nextState = {
2506
- ...state,
2507
- errorMessage: '',
2508
- events,
2509
- initial: false,
2510
- sessionId
2511
- };
2512
- return restoreSelectedEvent(nextState);
2513
- };
2514
- const loadEventsFromUri = async state => {
2515
- const sessionId = getSessionIdFromUri(state);
2516
- if (!sessionId) {
2517
- return getStateWithInvalidUri(state);
2518
- }
2519
- return loadEventsForSessionId(state, sessionId);
2520
- };
2521
- const refreshEvents = async state => {
2522
- const sessionId = state.sessionId || getSessionIdFromUri(state);
2523
- if (!sessionId) {
2524
- return getStateWithInvalidUri(state);
2525
- }
2526
- return loadEventsForSessionId(state, sessionId);
2527
- };
2528
-
2529
- const loadContent = async state => {
2530
- return loadEventsFromUri(state);
2531
- };
2532
-
2533
- const refresh = async state => {
2534
- return refreshEvents(state);
2535
- };
2536
-
2537
- const getCss = state => {
2538
- const tableWidth = clampTableWidth(state.width, state.tableWidth);
2539
- const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
2540
- return `
2541
- .ChatDebugView {
2542
- --ChatDebugViewDetailsWidth: ${detailsWidth}px;
2543
- --ChatDebugViewSashWidth: ${sashWidth}px;
2544
- --ChatDebugViewTableWidth: ${tableWidth}px;
2545
- padding: ${viewPadding}px;
2546
- display: flex;
2547
- flex-direction: column;
2548
- height: 100%;
2549
- box-sizing: border-box;
2550
- gap: 8px;
2551
- contain: strict;
2552
- }
2553
-
2554
- .ChatDebugView--devtools {
2555
- gap: 4px;
2556
- }
2557
-
2558
- .ChatDebugViewTop {
2559
- display: flex;
2560
- align-items: center;
2561
- gap: 12px;
2562
- flex-wrap: wrap;
2563
- contain: content;
2564
- }
2565
-
2566
- .ChatDebugViewTop--devtools {
2567
- align-items: stretch;
2568
- }
2569
-
2570
- .ChatDebugViewFilterInput {
2571
- flex: 1;
2572
- min-width: 0;
2573
- max-width: 500px;
2574
- contain: content;
2575
- }
2576
-
2577
- .ChatDebugViewFilterInput--devtools {
2578
- flex: 0 1 80px;
2579
- width: 100%;
2580
- max-width: 80px;
2581
- }
2582
-
2583
- .ChatDebugViewQuickFilterPill {
2584
- display: flex;
2585
- align-items: center;
2586
- justify-content: center;
2587
- min-height: 22px;
2588
- padding: 0 10px;
2589
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2590
- border-radius: 999px;
2591
- cursor: pointer;
2592
- white-space: nowrap;
2593
- transition:
2594
- background 120ms ease-out,
2595
- border-color 120ms ease-out,
2596
- color 120ms ease-out,
2597
- transform 120ms ease-out;
2598
- contain: content;
2599
- }
2600
-
2601
- .ChatDebugViewQuickFilterPill:not(.ChatDebugViewQuickFilterPillSelected):hover {
2602
- border-color: var(--vscode-focusBorder, #007fd4);
2603
- background: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 82%, transparent 18%);
2604
- color: var(--vscode-list-hoverForeground, inherit);
2605
- transform: translateY(-1px);
2606
- }
2607
-
2608
-
2609
- .ChatDebugViewQuickFilters {
2610
- display: flex;
2611
- align-items: center;
2612
- gap: 8px;
2613
- justify-content: center;
2614
- min-height: 28px;
2615
- font-size: 12px;
2616
- line-height: 1;
2617
- contain: content;
2618
- }
2619
-
2620
- .ChatDebugViewQuickFilterPillSelected {
2621
- border-color: var(--vscode-focusBorder, #007fd4);
2622
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
2623
- color: var(--vscode-list-activeSelectionForeground, inherit);
2624
- }
2625
-
2626
- .ChatDebugViewQuickFilterInput {
2627
- position: absolute;
2628
- opacity: 0;
2629
- pointer-events: none;
2630
- contain: content;
2631
- }
2632
-
2633
- .ChatDebugViewEvents {
2634
- display: flex;
2635
- flex-direction: column;
2636
- overflow: auto;
2637
- min-width: 0;
2638
- min-height: 0;
2639
- scrollbar-width: thin;
2640
- scrollbar-color: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4)) transparent;
2641
- contain: strict;
2642
- }
2643
-
2644
- .ChatDebugView--devtools .ChatDebugViewEvents {
2645
- border-radius: 6px;
2646
- margin-bottom: 0;
2647
- overflow: hidden;
2648
- }
2649
-
2650
- .ChatDebugViewEventsFullWidth {
2651
- flex: 1 1 100%;
2652
- }
2653
-
2654
- .ChatDebugViewDevtoolsMain {
2655
- display: flex;
2656
- flex-direction: column;
2657
- flex: 1;
2658
- align-items: stretch;
2659
- gap: 0;
2660
- min-width: 0;
2661
- min-height: 0;
2662
- contain: strict;
2663
- }
2664
-
2665
- .ChatDebugViewDevtoolsMain > .ChatDebugViewTimeline {
2666
- flex: 0 0 auto;
2667
- }
2668
-
2669
- .ChatDebugViewDevtoolsSplit {
2670
- display: flex;
2671
- flex: 1;
2672
- align-items: stretch;
2673
- gap: 0;
2674
- min-width: 0;
2675
- min-height: 0;
2676
- overflow: hidden;
2677
- contain: strict;
2678
- }
2679
-
2680
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents {
2681
- flex: 0 1 var(--ChatDebugViewTableWidth);
2682
- min-width: 0;
2683
- }
2684
-
2685
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents.ChatDebugViewEventsFullWidth {
2686
- flex: 1 1 100%;
2687
- }
2688
-
2689
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewDetails {
2690
- border-left: 0;
2691
- border-top-left-radius: 0;
2692
- border-bottom-left-radius: 0;
2693
- flex: 1;
2694
- }
2695
-
2696
- .ChatDebugViewSash {
2697
- flex: 0 0 var(--ChatDebugViewSashWidth);
2698
- position: relative;
2699
- cursor: col-resize;
2700
- display: flex;
2701
- justify-content: center;
2702
- min-height: 0;
2703
- contain: strict;
2704
- }
2705
-
2706
- .ChatDebugViewSashLine {
2707
- width: 1px;
2708
- height: 100%;
2709
- background: var(--vscode-editorWidget-border, #454545);
2710
- pointer-events: none;
2711
- contain: strict;
2712
- }
2713
-
2714
- .ChatDebugViewSash:hover .ChatDebugViewSashLine {
2715
- background: var(--vscode-focusBorder, #007fd4);
2716
- }
2717
-
2718
- .ChatDebugViewTable {
2719
- display: flex;
2720
- flex-direction: column;
2721
- min-height: 0;
2722
- flex: 1 1 auto;
2723
- contain: strict;
2724
- }
2725
-
2726
- .ChatDebugViewTimeline {
2727
- display: flex;
2728
- flex-direction: column;
2729
- gap: 6px;
2730
- padding: 6px ${timelineHorizontalPadding}px 8px;
2731
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
2732
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 82%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.12)) 18%);
2733
- contain: content;
2734
- }
2735
-
2736
- .ChatDebugViewTimelineTop {
2737
- display: flex;
2738
- align-items: center;
2739
- contain: content;
2740
- }
2741
-
2742
- .ChatDebugViewTimelineSummary {
2743
- display: flex;
2744
- align-items: center;
2745
- font-size: 12px;
2746
- line-height: 16px;
2747
- opacity: 0.8;
2748
- contain: content;
2749
- }
2750
-
2751
- .ChatDebugViewTimelineControls {
2752
- display: flex;
2753
- align-items: center;
2754
- gap: 8px;
2755
- flex-wrap: wrap;
2756
- contain: content;
2757
- }
2758
-
2759
- .ChatDebugViewTimelineBuckets {
2760
- display: flex;
2761
- align-items: end;
2762
- gap: 3px;
2763
- flex: 1 1 auto;
2764
- min-height: 52px;
2765
- pointer-events: none;
2766
- contain: strict;
2767
- }
2768
-
2769
- .ChatDebugViewTimelineInteractive {
2770
- display: flex;
2771
- position: relative;
2772
- min-height: 52px;
2773
- cursor: crosshair;
2774
- user-select: none;
2775
- contain: strict;
2776
- }
2777
-
2778
- .ChatDebugViewTimelineSelectionOverlay {
2779
- position: absolute;
2780
- inset: 0;
2781
- pointer-events: none;
2782
- contain: strict;
2783
- }
2784
-
2785
- .ChatDebugViewTimelineSelectionRange {
2786
- position: absolute;
2787
- top: 0;
2788
- bottom: 0;
2789
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 20%, transparent 80%);
2790
- border-left: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
2791
- border-right: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
2792
- contain: strict;
2793
- }
2794
-
2795
- .ChatDebugViewTimelineSelectionMarker {
2796
- position: absolute;
2797
- top: 0;
2798
- bottom: 0;
2799
- width: 1px;
2800
- margin-left: -0.5px;
2801
- background: var(--vscode-focusBorder, #007fd4);
2802
- box-shadow: 0 0 0 1px color-mix(in srgb, var(--vscode-focusBorder, #007fd4) 24%, transparent 76%);
2803
- contain: strict;
2804
- }
2805
-
2806
- .ChatDebugViewTimelineBucket {
2807
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 74%, transparent 26%);
2808
- --ChatDebugViewTimelineBucketBarBorderColor: transparent;
2809
- display: flex;
2810
- align-items: stretch;
2811
- flex: 1 1 10px;
2812
- min-width: 10px;
2813
- min-height: 52px;
2814
- contain: strict;
2815
- }
2816
-
2817
- .ChatDebugViewTimelineBucketSelected {
2818
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
2819
- --ChatDebugViewTimelineBucketBarBorderColor: var(--vscode-focusBorder, #007fd4);
2820
- }
2821
-
2822
- .ChatDebugViewTimelinePresetInput {
2823
- position: absolute;
2824
- opacity: 0;
2825
- pointer-events: none;
2826
- contain: content;
2827
- }
2828
-
2829
- .ChatDebugViewTimelineBucketBar {
2830
- display: flex;
2831
- flex-direction: column;
2832
- justify-content: flex-end;
2833
- gap: 2px;
2834
- padding: 6px 1px 2px;
2835
- border: 1px solid transparent;
2836
- border-radius: 2px;
2837
- width: 100%;
2838
- background: var(--ChatDebugViewTimelineBucketBarBackground);
2839
- border-color: var(--ChatDebugViewTimelineBucketBarBorderColor);
2840
- contain: strict;
2841
- }
2842
-
2843
- .ChatDebugViewTimelineBucketBarSelected {
2844
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
2845
- border-color: var(--vscode-focusBorder, #007fd4);
2846
- }
2847
-
2848
- .ChatDebugViewTimelineBucketUnit {
2849
- width: 100%;
2850
- height: 4px;
2851
- border-radius: 999px;
2852
- background: var(--vscode-charts-blue, #75beff);
2853
- contain: strict;
2854
- }
2855
-
2856
- .ChatDebugViewTimelineBucketUnitEmpty {
2857
- opacity: 0.35;
2858
- background: var(--vscode-editorWidget-border, #454545);
2859
- }
2860
-
2861
- .ChatDebugViewTableHeaderRow,
2862
- .ChatDebugViewEventRow {
2863
- display: flex;
2864
- align-items: center;
2865
- gap: 8px;
2866
- contain: content;
2867
- }
2868
-
2869
- .ChatDebugViewTableHeader {
2870
- padding: 3px 8px;
2871
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
2872
- background: var(--vscode-editorWidget-background, transparent);
2873
- position: sticky;
2874
- top: 0;
2875
- z-index: 1;
2876
- contain: content;
2877
- }
2878
-
2879
- .ChatDebugViewHeaderCell {
2880
- display: flex;
2881
- align-items: center;
2882
- overflow: hidden;
2883
- text-overflow: ellipsis;
2884
- white-space: nowrap;
2885
- min-width: 0;
2886
- font-size: 11px;
2887
- letter-spacing: 0.04em;
2888
- opacity: 0.8;
2889
- contain: content;
2890
- }
2891
-
2892
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(1) {
2893
- flex: 1 1 140px;
2894
- min-width: 0;
2895
- }
2896
-
2897
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(2) {
2898
- flex: 0 0 90px;
2899
- justify-content: flex-end;
2900
- }
2901
-
2902
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(3) {
2903
- flex: 0 0 96px;
2904
- justify-content: flex-end;
2905
- }
2906
-
2907
- .ChatDebugViewTableBody {
2908
- display: flex;
2909
- flex-direction: column;
2910
- overflow: auto;
2911
- min-height: 0;
2912
- flex: 1 1 auto;
2913
- contain: strict;
2914
- }
2915
-
2916
- .ChatDebugViewEventRowLabel {
2917
- display: block;
2918
- contain: content;
2919
- }
2920
-
2921
- .ChatDebugViewEventRowLabelSelected .ChatDebugViewEventRow,
2922
- .ChatDebugViewEventRowSelected {
2923
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
2924
- color: var(--vscode-list-activeSelectionForeground, inherit);
2925
- }
2926
-
2927
- .ChatDebugViewEventRowInput {
2928
- position: absolute;
2929
- opacity: 0;
2930
- pointer-events: none;
2931
- contain: content;
2932
- }
2933
-
2934
- .ChatDebugViewEventRow {
2935
- padding: 2px 8px;
2936
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 92%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 8%);
2937
- cursor: default;
2938
- }
2939
-
2940
- .ChatDebugViewTableBody > .ChatDebugViewEventRow:nth-child(even) {
2941
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 84%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 16%);
2942
- }
2943
-
2944
- .ChatDebugViewEventRow:hover {
2945
- background: var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31));
2946
- color: var(--vscode-list-hoverForeground, inherit);
2947
- }
2589
+ }
2590
+ return {
2591
+ ...state,
2592
+ timelineSelectionFocusSeconds: seconds
2593
+ };
2594
+ };
2948
2595
 
2949
- .ChatDebugViewCell {
2950
- display: flex;
2951
- align-items: center;
2952
- overflow: hidden;
2953
- text-overflow: ellipsis;
2954
- white-space: nowrap;
2955
- min-width: 0;
2956
- pointer-events: none;
2957
- contain: content;
2958
- }
2596
+ const handleTimelinePointerUp = (state, eventX) => {
2597
+ if (!state.timelineSelectionActive) {
2598
+ return state;
2599
+ }
2600
+ const timelineEvents = getTimelineEvents(state);
2601
+ const timelineLeft = getTimelineLeft(state);
2602
+ const timelineWidth = getTimelineWidth(state);
2603
+ const clientX = state.x + eventX;
2604
+ const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2605
+ if (focusSeconds === undefined) {
2606
+ return clearTimelineSelectionState(state);
2607
+ }
2608
+ const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
2609
+ const focus = Number.parseFloat(focusSeconds);
2610
+ const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
2611
+ const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
2612
+ const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
2613
+ return clearTimelineSelectionState(nextState);
2614
+ };
2959
2615
 
2960
- .ChatDebugViewCellType {
2961
- flex: 1 1 140px;
2962
- min-width: 0;
2963
- }
2616
+ const handleUseDevtoolsLayout = (state, checked) => {
2617
+ const useDevtoolsLayout = getBoolean(checked);
2618
+ const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
2619
+ return {
2620
+ ...state,
2621
+ selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
2622
+ selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
2623
+ selectedEventIndex,
2624
+ useDevtoolsLayout
2625
+ };
2626
+ };
2964
2627
 
2965
- .ChatDebugViewCellTime {
2966
- flex: 1 1 180px;
2967
- min-width: 0;
2968
- }
2628
+ const handleShowEventStreamFinishedEvents = (state, checked) => {
2629
+ const nextState = {
2630
+ ...state,
2631
+ showEventStreamFinishedEvents: getBoolean(checked)
2632
+ };
2633
+ return withPreservedSelection$1(state, nextState);
2634
+ };
2635
+ const handleShowInputEvents = (state, checked) => {
2636
+ const nextState = {
2637
+ ...state,
2638
+ showInputEvents: getBoolean(checked)
2639
+ };
2640
+ return withPreservedSelection$1(state, nextState);
2641
+ };
2642
+ const handleShowResponsePartEvents = (state, checked) => {
2643
+ const nextState = {
2644
+ ...state,
2645
+ showResponsePartEvents: getBoolean(checked)
2646
+ };
2647
+ return withPreservedSelection$1(state, nextState);
2648
+ };
2969
2649
 
2970
- .ChatDebugViewCellDuration {
2971
- flex: 0 0 90px;
2972
- justify-content: flex-end;
2973
- text-align: right;
2974
- }
2650
+ const loadContent = async (state, savedState) => {
2651
+ return loadEventsFromUri(restoreSavedState(state, savedState));
2652
+ };
2975
2653
 
2976
- .ChatDebugViewCellStatus {
2977
- flex: 0 0 64px;
2978
- justify-content: flex-end;
2979
- text-align: right;
2654
+ const getCss = state => {
2655
+ const tableWidth = clampTableWidth(state.width, state.tableWidth);
2656
+ const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
2657
+ return `
2658
+ .ChatDebugView {
2659
+ --ChatDebugViewDetailsWidth: ${detailsWidth}px;
2660
+ --ChatDebugViewSashWidth: ${sashWidth}px;
2661
+ --ChatDebugViewTableWidth: ${tableWidth}px;
2662
+ padding: ${viewPadding}px;
2980
2663
  }
2981
2664
 
2982
- .ChatDebugViewCellStatusError {
2983
- color: var(--vscode-errorForeground, #f14c4c);
2984
- }
2985
2665
 
2986
- .ChatDebugViewDetails {
2987
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2988
- border-radius: 6px;
2989
- overflow: hidden;
2990
- min-width: 0;
2991
- min-height: 0;
2992
- display: flex;
2993
- flex-direction: column;
2666
+ .ChatDebugViewDetails {
2994
2667
  contain: strict;
2995
2668
  }
2996
2669
 
2997
2670
  .ChatDebugViewDetailsTop {
2998
- display: flex;
2999
- align-items: stretch;
3000
- justify-content: flex-start;
3001
- gap: 8px;
3002
- padding: 0 8px;
3003
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3004
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 72%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.18)) 28%);
3005
- contain: content;
3006
- }
3007
-
3008
- .ChatDebugViewDetailsClose {
3009
- width: 18px;
3010
- height: 18px;
3011
- appearance: none;
3012
- border: none;
3013
- border-radius: 4px;
3014
- cursor: pointer;
3015
- position: relative;
3016
- color: var(--vscode-foreground, #cccccc);
3017
- background: transparent;
3018
- align-self: center;
3019
- flex: 0 0 auto;
2671
+ height: 33px;
3020
2672
  contain: strict;
3021
2673
  }
3022
2674
 
3023
- .ChatDebugViewDetailsClose:hover {
3024
- background: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
3025
- }
3026
-
3027
- .ChatDebugViewDetailsClose::before,
3028
- .ChatDebugViewDetailsClose::after {
3029
- content: '';
3030
- position: absolute;
3031
- left: 50%;
3032
- top: 50%;
3033
- width: 10px;
3034
- height: 1px;
3035
- background: currentColor;
3036
- }
3037
-
3038
- .ChatDebugViewDetailsClose::before {
3039
- transform: translate(-50%, -50%) rotate(45deg);
3040
- }
3041
-
3042
- .ChatDebugViewDetailsClose::after {
3043
- transform: translate(-50%, -50%) rotate(-45deg);
3044
- }
3045
-
3046
- .ChatDebugViewDetailsBody {
2675
+ .ChatDebugViewDetailsBottom {
3047
2676
  display: flex;
3048
- flex-direction: column;
3049
- overflow: hidden;
3050
- padding: 0;
3051
- flex: 1 1 auto;
3052
- min-height: 0;
3053
- align-items: stretch;
3054
2677
  contain: strict;
2678
+ flex:1
2679
+
2680
+ }
2681
+ .ChatDebugViewEvent {
2682
+ contain: content
3055
2683
  }
3056
2684
 
3057
- .ChatDebugViewDetailsTabs {
3058
- display: flex;
3059
- align-items: center;
3060
- flex: 1 1 auto;
3061
- gap: 2px;
3062
- min-width: 0;
3063
- padding: 0;
3064
- overflow-x: auto;
3065
- contain: content;
2685
+ .row {
2686
+ flex-shrink: 0;
3066
2687
  }
3067
2688
 
3068
- .ChatDebugViewDetailsTab {
3069
- display: flex;
2689
+ .ChatDebugViewRefreshButton {
2690
+ display: inline-flex;
3070
2691
  align-items: center;
3071
2692
  justify-content: center;
3072
- min-height: 32px;
2693
+ flex: none;
2694
+ min-height: 28px;
3073
2695
  padding: 0 10px;
3074
- appearance: none;
3075
- background: transparent;
3076
- border: 0;
3077
- border-bottom: 2px solid transparent;
3078
- color: var(--vscode-descriptionForeground, var(--vscode-foreground, #cccccc));
3079
- cursor: pointer;
3080
- white-space: nowrap;
3081
- contain: content;
3082
- }
3083
-
3084
- .ChatDebugViewDetailsTab:hover {
3085
- color: var(--vscode-foreground, #cccccc);
3086
- }
3087
-
3088
- .ChatDebugViewDetailsTabSelected {
3089
- border-bottom-color: var(--vscode-focusBorder, #007fd4);
3090
- color: var(--vscode-focusBorder, #007fd4);
3091
- }
3092
-
3093
- .ChatDebugViewDetailsPanel {
3094
- display: flex;
3095
- flex-direction: column;
3096
- overflow: auto;
3097
- padding: 8px;
3098
- flex: 1 1 auto;
3099
- min-height: 0;
3100
- align-items: flex-start;
3101
- contain: strict;
3102
- }
3103
-
3104
- .ChatDebugViewEvents::-webkit-scrollbar {
3105
- width: 10px;
3106
- height: 10px;
3107
- }
3108
-
3109
- .ChatDebugViewEvents::-webkit-scrollbar-track {
3110
- background: transparent;
3111
- }
3112
-
3113
- .ChatDebugViewEvents::-webkit-scrollbar-thumb {
3114
- background: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4));
3115
- border-radius: 999px;
3116
- border: 2px solid transparent;
3117
- background-clip: content-box;
3118
- }
3119
-
3120
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:hover {
3121
- background: var(--vscode-scrollbarSlider-hoverBackground, rgba(100, 100, 100, 0.7));
3122
- }
3123
-
3124
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:active {
3125
- background: var(--vscode-scrollbarSlider-activeBackground, rgba(191, 191, 191, 0.4));
3126
- }
3127
-
3128
- .ChatDebugViewEvent {
3129
- display: flex;
3130
- flex-direction: column;
3131
- width: max-content;
3132
- min-width: 100%;
3133
- margin: 0;
3134
- padding: 8px;
3135
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2696
+ border: 1px solid rgba(255, 255, 255, 0.16);
3136
2697
  border-radius: 6px;
3137
- margin-bottom: 8px;
3138
- white-space: nowrap;
3139
- font-family: var(--vscode-editor-font-family, monospace);
2698
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.04));
2699
+ color: inherit;
2700
+ font: inherit;
3140
2701
  font-size: 12px;
3141
- user-select: text;
3142
- contain: content;
3143
- }
3144
-
3145
- .row {
3146
- display: flex;
3147
- align-items: baseline;
3148
- gap: 12px;
3149
- min-width: 100%;
3150
- width: max-content;
2702
+ font-weight: 500;
2703
+ line-height: 1;
3151
2704
  white-space: nowrap;
3152
- contain: strict;
3153
- height: 20px;
3154
- }
3155
-
3156
- .ChatDebugViewEventLineNumber {
3157
- display: flex;
3158
- justify-content: flex-end;
3159
- flex: 0 0 3ch;
3160
- opacity: 0.6;
3161
- user-select: none;
3162
- contain: content;
3163
- }
3164
-
3165
- .ChatDebugViewEventLineContent {
3166
- display: flex;
3167
- white-space: pre;
3168
- contain: content;
3169
- }
3170
-
3171
- .ChatDebugViewDetailsPanel > .ChatDebugViewEvent {
3172
- border: 0;
3173
- border-radius: 0;
3174
- margin-bottom: 0;
3175
- }
3176
-
3177
- .ChatDebugViewTiming {
3178
- display: flex;
3179
- flex-direction: column;
3180
- width: 100%;
3181
- contain: strict;
3182
- flex: 1;
3183
- }
3184
-
3185
- .ChatDebugViewTimingRow {
3186
- display: flex;
3187
- align-items: center;
3188
- justify-content: space-between;
3189
- gap: 12px;
3190
- padding: 8px 10px;
3191
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3192
- contain: content;
3193
- }
3194
-
3195
- .ChatDebugViewTimingRow:last-child {
3196
- border-bottom: 0;
3197
- }
3198
-
3199
- .ChatDebugViewTimingLabel {
3200
- opacity: 0.8;
3201
- contain: content;
3202
- }
3203
-
3204
- .ChatDebugViewTimingValue {
3205
- text-align: right;
3206
- font-family: var(--vscode-editor-font-family, monospace);
3207
- contain: content;
3208
- }
3209
-
3210
- .ChatDebugViewEmpty {
3211
- display: flex;
3212
- align-items: center;
3213
- opacity: 0.8;
3214
- contain: content;
3215
- }
3216
-
3217
- .ChatDebugViewError {
3218
- display: flex;
3219
- color: var(--vscode-errorForeground, #f14c4c);
3220
- white-space: normal;
3221
- contain: content;
3222
- }
3223
-
3224
- .TokenText {
3225
- color: var(--vscode-editor-foreground, inherit);
3226
- }
3227
-
3228
- .TokenKey {
3229
- color: var(--vscode-symbolIcon-propertyForeground, var(--vscode-editor-foreground, inherit));
3230
- }
3231
-
3232
- .TokenString {
3233
- color: var(--vscode-debugTokenExpression-string, var(--vscode-charts-green, #89d185));
3234
- }
3235
-
3236
- .TokenNumeric {
3237
- color: var(--vscode-debugTokenExpression-number, var(--vscode-charts-blue, #75beff));
2705
+ cursor: pointer;
2706
+ transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease;
3238
2707
  }
3239
2708
 
3240
- .TokenBoolean {
3241
- color: var(--vscode-debugTokenExpression-boolean, var(--vscode-charts-yellow, #dcdcaa));
2709
+ .ChatDebugViewRefreshButton:hover {
2710
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.08));
2711
+ border-color: rgba(255, 255, 255, 0.24);
3242
2712
  }
3243
2713
 
3244
- .ChatOrderedList{
3245
- display:flex;
3246
- flex-direction:column;
3247
- margin:0;
3248
- padding:0;
3249
- padding-left:10px;
3250
- contain: content;
2714
+ .ChatDebugViewRefreshButton:active {
2715
+ transform: translateY(1px);
3251
2716
  }
3252
2717
 
3253
- .ChatOrderedListItem{
3254
- display:flex;
3255
- margin:0;
3256
- padding:0;
3257
- contain: content;
2718
+ .ChatDebugViewRefreshButton:focus-visible {
2719
+ outline: 2px solid rgba(255, 255, 255, 0.4);
2720
+ outline-offset: 1px;
3258
2721
  }
3259
2722
 
3260
- .ChatToolCalls{
3261
- display:flex;
3262
- flex-direction:column;
3263
- margin:0;
3264
- padding:0;
3265
- contain: content;
2723
+ .ChatDebugViewEventRow:hover {
2724
+ background: var(--ListHoverBackground);
2725
+ color: var(--ListHoverForeground);
3266
2726
  }
3267
2727
  `;
3268
2728
  };
@@ -3571,9 +3031,8 @@ const diffTree = (oldNodes, newNodes) => {
3571
3031
  const ChatDebugView = 'ChatDebugView';
3572
3032
  const ChatDebugViewDevtools = 'ChatDebugView--devtools';
3573
3033
  const ChatDebugViewDetails = 'ChatDebugViewDetails';
3574
- const ChatDebugViewDetailsBody = 'ChatDebugViewDetailsBody';
3034
+ const ChatDebugViewDetailsBottom = 'ChatDebugViewDetailsBottom';
3575
3035
  const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
3576
- const ChatDebugViewDetailsPanel = 'ChatDebugViewDetailsPanel';
3577
3036
  const ChatDebugViewDetailsTab = 'ChatDebugViewDetailsTab';
3578
3037
  const ChatDebugViewDetailsTabSelected = 'ChatDebugViewDetailsTabSelected';
3579
3038
  const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
@@ -3592,6 +3051,7 @@ const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
3592
3051
  const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
3593
3052
  const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
3594
3053
  const ChatDebugViewHeaderCell = 'ChatDebugViewHeaderCell';
3054
+ const ChatDebugViewRefreshButton = 'ChatDebugViewRefreshButton';
3595
3055
  const ChatDebugViewQuickFilterInput = 'ChatDebugViewQuickFilterInput';
3596
3056
  const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
3597
3057
  const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
@@ -3602,6 +3062,7 @@ const ChatDebugViewTable = 'ChatDebugViewTable';
3602
3062
  const ChatDebugViewTableBody = 'ChatDebugViewTableBody';
3603
3063
  const ChatDebugViewTableHeader = 'ChatDebugViewTableHeader';
3604
3064
  const ChatDebugViewTableHeaderRow = 'ChatDebugViewTableHeaderRow';
3065
+ const TableRowEven = 'TableRowEven';
3605
3066
  const ChatDebugViewTimeline = 'ChatDebugViewTimeline';
3606
3067
  const ChatDebugViewTimelineBucket = 'ChatDebugViewTimelineBucket';
3607
3068
  const ChatDebugViewTimelineBucketBar = 'ChatDebugViewTimelineBucketBar';
@@ -3611,7 +3072,6 @@ const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
3611
3072
  const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
3612
3073
  const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
3613
3074
  const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
3614
- const ChatDebugViewTimelinePresetInput = 'ChatDebugViewTimelinePresetInput';
3615
3075
  const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
3616
3076
  const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
3617
3077
  const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
@@ -3632,11 +3092,11 @@ const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
3632
3092
  const ChatDebugViewCellType = 'ChatDebugViewCellType';
3633
3093
  const InputBox = 'InputBox';
3634
3094
  const Row = 'row';
3635
- const TokenBoolean = 'TokenBoolean';
3636
- const TokenKey = 'TokenKey';
3637
- const TokenNumeric = 'TokenNumeric';
3638
- const TokenString = 'TokenString';
3639
- const TokenText = 'TokenText';
3095
+ const TokenBoolean = 'Token TokenBoolean';
3096
+ const TokenKey = 'Token TokenKey';
3097
+ const TokenNumeric = 'Token TokenNumeric';
3098
+ const TokenString = 'Token TokenString';
3099
+ const TokenText = 'Token TokenText';
3640
3100
  const joinClassNames = (...classNames) => {
3641
3101
  return classNames.filter(Boolean).join(' ');
3642
3102
  };
@@ -3670,11 +3130,24 @@ const HandleTimelineDoubleClick = 17;
3670
3130
  const HandleTableKeyDown = 18;
3671
3131
  const HandleTimelineRangePreset = 19;
3672
3132
  const HandleCloseDetails = 20;
3133
+ const HandleClickRefresh = 21;
3673
3134
 
3135
+ const getRefreshButtonDom = () => {
3136
+ return [{
3137
+ 'aria-label': 'Refresh events',
3138
+ childCount: 1,
3139
+ className: ChatDebugViewRefreshButton,
3140
+ name: Refresh,
3141
+ onClick: HandleClickRefresh,
3142
+ type: Button$1,
3143
+ value: Refresh
3144
+ }, text('Refresh')];
3145
+ };
3674
3146
  const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
3147
+ const refreshButtonDom = getRefreshButtonDom();
3675
3148
  if (useDevtoolsLayout) {
3676
3149
  return [{
3677
- childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
3150
+ childCount: 2 + (quickFilterNodes.length > 0 ? 1 : 0),
3678
3151
  className: joinClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
3679
3152
  onContextMenu: HandleHeaderContextMenu,
3680
3153
  type: Search
@@ -3688,10 +3161,10 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3688
3161
  placeholder: 'Filter events',
3689
3162
  type: Input,
3690
3163
  value: filterValue
3691
- }, ...quickFilterNodes];
3164
+ }, ...quickFilterNodes, ...refreshButtonDom];
3692
3165
  }
3693
3166
  return [{
3694
- childCount: 1,
3167
+ childCount: 2,
3695
3168
  className: ChatDebugViewTop,
3696
3169
  onContextMenu: HandleHeaderContextMenu,
3697
3170
  type: Search
@@ -3705,7 +3178,7 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3705
3178
  placeholder: 'Filter events',
3706
3179
  type: Input,
3707
3180
  value: filterValue
3708
- }];
3181
+ }, ...refreshButtonDom];
3709
3182
  };
3710
3183
 
3711
3184
  const getDurationText = event => {
@@ -3801,7 +3274,7 @@ const getTabNodes = selectedDetailTab => {
3801
3274
  onClick: HandleDetailTab,
3802
3275
  role: 'tab',
3803
3276
  tabIndex: isSelected ? 0 : -1,
3804
- type: Button,
3277
+ type: Button$1,
3805
3278
  value: detailTab
3806
3279
  }, text(getDetailTabLabel(detailTab))];
3807
3280
  });
@@ -3814,7 +3287,7 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
3814
3287
  return [{
3815
3288
  childCount: 2,
3816
3289
  className: ChatDebugViewDetails,
3817
- type: Div
3290
+ type: Section
3818
3291
  }, {
3819
3292
  childCount: 2,
3820
3293
  className: ChatDebugViewDetailsTop,
@@ -3826,7 +3299,7 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
3826
3299
  name: CloseDetails,
3827
3300
  onChange: HandleCloseDetails,
3828
3301
  onClick: HandleCloseDetails,
3829
- type: Button,
3302
+ type: Button$1,
3830
3303
  value: 'close'
3831
3304
  }, {
3832
3305
  'aria-label': 'Detail sections',
@@ -3835,14 +3308,9 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
3835
3308
  role: 'tablist',
3836
3309
  type: Div
3837
3310
  }, ...getTabNodes(selectedDetailTab), {
3838
- childCount: 1,
3839
- className: ChatDebugViewDetailsBody,
3840
- role: 'document',
3841
- type: Div
3842
- }, {
3843
3311
  'aria-labelledby': getTabId(selectedDetailTab),
3844
3312
  childCount: 1,
3845
- className: ChatDebugViewDetailsPanel,
3313
+ className: ChatDebugViewDetailsBottom,
3846
3314
  id: getPanelId(selectedDetailTab),
3847
3315
  onContextMenu: HandleDetailsContextMenu,
3848
3316
  role: 'tabpanel',
@@ -3932,12 +3400,13 @@ const getStatusText = event => {
3932
3400
 
3933
3401
  const getDevtoolsRows = (events, selectedEventIndex) => {
3934
3402
  return events.flatMap((event, i) => {
3403
+ const isEvenRow = i % 2 === 1;
3935
3404
  const isSelected = selectedEventIndex === i;
3936
3405
  const isErrorStatus = hasErrorStatus(event);
3937
3406
  const rowIndex = String(i);
3938
3407
  return [{
3939
3408
  childCount: 3,
3940
- className: joinClassNames(ChatDebugViewEventRow, isSelected && ChatDebugViewEventRowSelected),
3409
+ className: joinClassNames(ChatDebugViewEventRow, isEvenRow && TableRowEven, isSelected && ChatDebugViewEventRowSelected),
3941
3410
  'data-index': rowIndex,
3942
3411
  type: Tr
3943
3412
  }, {
@@ -3964,28 +3433,53 @@ const getEmptyStateDom = emptyMessage => {
3964
3433
  }, text(emptyMessage)];
3965
3434
  };
3966
3435
 
3967
- const pushToken = (segments, className, value) => {
3968
- if (!value) {
3969
- return segments;
3436
+ const isDigit = character => {
3437
+ return character !== undefined && character >= '0' && character <= '9';
3438
+ };
3439
+ const isWhitespace = character => {
3440
+ return character === ' ' || character === '\n' || character === '\r' || character === '\t';
3441
+ };
3442
+ const getNumberEnd = (json, start) => {
3443
+ let i = start;
3444
+ if (json[i] === '-') {
3445
+ i++;
3970
3446
  }
3971
- const lastSegment = segments.at(-1);
3972
- if (lastSegment && lastSegment.className === className) {
3973
- const merged = {
3974
- className,
3975
- value: lastSegment.value + value
3976
- };
3977
- return [...segments.slice(0, -1), merged];
3447
+ if (json[i] === '0') {
3448
+ i++;
3449
+ } else {
3450
+ if (!isDigit(json[i])) {
3451
+ return start;
3452
+ }
3453
+ while (isDigit(json[i])) {
3454
+ i++;
3455
+ }
3978
3456
  }
3979
- return [...segments, {
3980
- className,
3981
- value
3982
- }];
3457
+ if (json[i] === '.') {
3458
+ const decimalStart = i;
3459
+ i++;
3460
+ if (!isDigit(json[i])) {
3461
+ return decimalStart;
3462
+ }
3463
+ while (isDigit(json[i])) {
3464
+ i++;
3465
+ }
3466
+ }
3467
+ if (json[i] === 'e' || json[i] === 'E') {
3468
+ const exponentStart = i;
3469
+ i++;
3470
+ if (json[i] === '+' || json[i] === '-') {
3471
+ i++;
3472
+ }
3473
+ if (!isDigit(json[i])) {
3474
+ return exponentStart;
3475
+ }
3476
+ while (isDigit(json[i])) {
3477
+ i++;
3478
+ }
3479
+ }
3480
+ return i;
3983
3481
  };
3984
-
3985
- const numberRegex = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
3986
- const whitespaceRegex = /\s/u;
3987
- const getTokenSegments = json => {
3988
- let segments = [];
3482
+ const forEachTokenSegment = (json, onToken) => {
3989
3483
  let i = 0;
3990
3484
  while (i < json.length) {
3991
3485
  const character = json[i];
@@ -4004,40 +3498,38 @@ const getTokenSegments = json => {
4004
3498
  }
4005
3499
  i++;
4006
3500
  }
4007
- const tokenValue = json.slice(start, i);
4008
3501
  let lookAheadIndex = i;
4009
- while (lookAheadIndex < json.length && whitespaceRegex.test(json[lookAheadIndex])) {
3502
+ while (lookAheadIndex < json.length && isWhitespace(json[lookAheadIndex])) {
4010
3503
  lookAheadIndex++;
4011
3504
  }
4012
3505
  const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
4013
- segments = pushToken(segments, className, tokenValue);
3506
+ onToken(className, json.slice(start, i));
4014
3507
  continue;
4015
3508
  }
4016
- const numberMatch = numberRegex.exec(json.slice(i));
4017
- if (numberMatch) {
4018
- segments = pushToken(segments, TokenNumeric, numberMatch[0]);
4019
- i += numberMatch[0].length;
3509
+ const numberEnd = getNumberEnd(json, i);
3510
+ if (numberEnd > i) {
3511
+ onToken(TokenNumeric, json.slice(i, numberEnd));
3512
+ i = numberEnd;
4020
3513
  continue;
4021
3514
  }
4022
3515
  if (json.startsWith('true', i)) {
4023
- segments = pushToken(segments, TokenBoolean, 'true');
3516
+ onToken(TokenBoolean, 'true');
4024
3517
  i += 4;
4025
3518
  continue;
4026
3519
  }
4027
3520
  if (json.startsWith('false', i)) {
4028
- segments = pushToken(segments, TokenBoolean, 'false');
3521
+ onToken(TokenBoolean, 'false');
4029
3522
  i += 5;
4030
3523
  continue;
4031
3524
  }
4032
3525
  if (json.startsWith('null', i)) {
4033
- segments = pushToken(segments, TokenBoolean, 'null');
3526
+ onToken(TokenBoolean, 'null');
4034
3527
  i += 4;
4035
3528
  continue;
4036
3529
  }
4037
- segments = pushToken(segments, TokenText, character);
3530
+ onToken(TokenText, character);
4038
3531
  i++;
4039
3532
  }
4040
- return segments;
4041
3533
  };
4042
3534
 
4043
3535
  const getJsonLines = value => {
@@ -4048,25 +3540,34 @@ const getJsonLines = value => {
4048
3540
  value: String(json)
4049
3541
  }]];
4050
3542
  }
4051
- const segments = getTokenSegments(json);
4052
3543
  const lines = [];
4053
3544
  let currentLine = [];
4054
- for (const segment of segments) {
4055
- const parts = segment.value.split('\n');
4056
- for (let i = 0; i < parts.length; i++) {
4057
- const part = parts[i];
4058
- if (part) {
4059
- currentLine.push({
4060
- className: segment.className,
4061
- value: part
4062
- });
4063
- }
4064
- if (i < parts.length - 1) {
3545
+ const pushLineSegment = (className, lineValue) => {
3546
+ if (!lineValue) {
3547
+ return;
3548
+ }
3549
+ const lastSegment = currentLine.at(-1);
3550
+ if (lastSegment && lastSegment.className === className) {
3551
+ lastSegment.value += lineValue;
3552
+ return;
3553
+ }
3554
+ currentLine.push({
3555
+ className,
3556
+ value: lineValue
3557
+ });
3558
+ };
3559
+ forEachTokenSegment(json, (className, segmentValue) => {
3560
+ let start = 0;
3561
+ for (let i = 0; i < segmentValue.length; i++) {
3562
+ if (segmentValue[i] === '\n') {
3563
+ pushLineSegment(className, segmentValue.slice(start, i));
4065
3564
  lines.push(currentLine);
4066
3565
  currentLine = [];
3566
+ start = i + 1;
4067
3567
  }
4068
3568
  }
4069
- }
3569
+ pushLineSegment(className, segmentValue.slice(start));
3570
+ });
4070
3571
  lines.push(currentLine);
4071
3572
  return lines;
4072
3573
  };
@@ -4125,6 +3626,33 @@ const hasOwn = (event, key) => {
4125
3626
  const isChatMessageUpdatedEvent = event => {
4126
3627
  return event.type === 'chat-message-updated';
4127
3628
  };
3629
+ const isChatMessageAddedEvent = event => {
3630
+ return event.type === 'chat-message-added';
3631
+ };
3632
+ const getPreviewMessageText = event => {
3633
+ if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
3634
+ return event.text;
3635
+ }
3636
+ if (!isChatMessageAddedEvent(event)) {
3637
+ return undefined;
3638
+ }
3639
+ const {
3640
+ message
3641
+ } = event;
3642
+ if (!message || typeof message !== 'object') {
3643
+ return undefined;
3644
+ }
3645
+ if (!Object.hasOwn(message, 'text')) {
3646
+ return undefined;
3647
+ }
3648
+ const {
3649
+ text
3650
+ } = message;
3651
+ if (typeof text !== 'string') {
3652
+ return undefined;
3653
+ }
3654
+ return text;
3655
+ };
4128
3656
  const getPreviewName = event => {
4129
3657
  if (typeof event.name === 'string' && event.name) {
4130
3658
  return event.name;
@@ -4144,8 +3672,9 @@ const shouldIncludeArguments = (event, name) => {
4144
3672
  return true;
4145
3673
  };
4146
3674
  const getPreviewEvent = event => {
4147
- if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
4148
- return event.text;
3675
+ const previewMessageText = getPreviewMessageText(event);
3676
+ if (previewMessageText !== undefined) {
3677
+ return previewMessageText;
4149
3678
  }
4150
3679
  const name = getPreviewName(event);
4151
3680
  const previewEvent = {
@@ -4230,9 +3759,12 @@ const formatPercent = value => {
4230
3759
  return `${Number(value.toFixed(3))}%`;
4231
3760
  };
4232
3761
 
4233
- const getBucketUnitDom = unitCount => {
3762
+ const getBucketUnitDom = (unitCount, presetValue) => {
4234
3763
  if (unitCount === 0) {
4235
3764
  return [{
3765
+ ...(presetValue ? {
3766
+ 'data-value': presetValue
3767
+ } : {}),
4236
3768
  childCount: 0,
4237
3769
  className: joinClassNames(ChatDebugViewTimelineBucketUnit, ChatDebugViewTimelineBucketUnitEmpty),
4238
3770
  type: Div
@@ -4241,6 +3773,9 @@ const getBucketUnitDom = unitCount => {
4241
3773
  return Array.from({
4242
3774
  length: unitCount
4243
3775
  }).fill({
3776
+ ...(presetValue ? {
3777
+ 'data-value': presetValue
3778
+ } : {}),
4244
3779
  childCount: 0,
4245
3780
  className: ChatDebugViewTimelineBucketUnit,
4246
3781
  type: Div
@@ -4250,23 +3785,17 @@ const getBucketUnitDom = unitCount => {
4250
3785
  const getBucketDom = bucket => {
4251
3786
  const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
4252
3787
  return [{
4253
- childCount: 2,
3788
+ childCount: 1,
4254
3789
  className: joinClassNames(ChatDebugViewTimelineBucket, bucket.isSelected && ChatDebugViewTimelineBucketSelected),
4255
- type: Label
4256
- }, {
4257
- checked: false,
4258
- childCount: 0,
4259
- className: ChatDebugViewTimelinePresetInput,
4260
- inputType: 'radio',
4261
- name: TimelineRangePreset,
4262
- onChange: HandleTimelineRangePreset,
4263
- type: Input,
4264
- value: presetValue
3790
+ 'data-value': presetValue,
3791
+ onClick: HandleTimelineRangePreset,
3792
+ type: Div
4265
3793
  }, {
4266
3794
  childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
4267
3795
  className: joinClassNames(ChatDebugViewTimelineBucketBar, bucket.isSelected && ChatDebugViewTimelineBucketBarSelected),
3796
+ 'data-value': presetValue,
4268
3797
  type: Div
4269
- }, ...getBucketUnitDom(bucket.unitCount)];
3798
+ }, ...getBucketUnitDom(bucket.unitCount, presetValue)];
4270
3799
  };
4271
3800
 
4272
3801
  const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
@@ -4322,7 +3851,7 @@ const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSecon
4322
3851
  return [{
4323
3852
  childCount: 2,
4324
3853
  className: ChatDebugViewTimeline,
4325
- type: Div
3854
+ type: Section
4326
3855
  }, {
4327
3856
  childCount: 1,
4328
3857
  className: ChatDebugViewTimelineTop,
@@ -4363,10 +3892,12 @@ const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvent
4363
3892
  return [{
4364
3893
  childCount: mainChildCount,
4365
3894
  className: ChatDebugViewDevtoolsMain,
3895
+ role: 'none',
4366
3896
  type: Div
4367
3897
  }, ...timelineNodes, {
4368
3898
  childCount: splitChildCount,
4369
3899
  className: ChatDebugViewDevtoolsSplit,
3900
+ role: 'none',
4370
3901
  type: Div
4371
3902
  }, {
4372
3903
  childCount: 1,
@@ -4526,11 +4057,19 @@ const render2 = (uid, diffResult) => {
4526
4057
 
4527
4058
  const renderEventListeners = () => {
4528
4059
  return [{
4060
+ name: HandleHeaderContextMenu,
4061
+ params: ['handleHeaderContextMenu'],
4062
+ preventDefault: true
4063
+ }, {
4529
4064
  name: HandleEventRowClick,
4530
- params: ['handleEventRowClick', 'event.target.dataset.index', 'event.button']
4065
+ params: ['handleEventRowClick', 'event.target.dataset.index', Button]
4531
4066
  }, {
4532
4067
  name: HandleTableBodyContextMenu,
4533
- params: ['handleTableBodyContextMenu'],
4068
+ params: ['handleTableBodyContextMenu', ClientX, ClientY],
4069
+ preventDefault: true
4070
+ }, {
4071
+ name: HandleDetailsContextMenu,
4072
+ params: ['handleDetailsContextMenu'],
4534
4073
  preventDefault: true
4535
4074
  }, {
4536
4075
  name: HandleFilterInput,
@@ -4543,10 +4082,16 @@ const renderEventListeners = () => {
4543
4082
  params: ['handleDetailTab', TargetValue]
4544
4083
  }, {
4545
4084
  name: HandleTimelineRangePreset,
4546
- params: ['handleTimelineRangePreset', TargetValue]
4085
+ params: ['handleTimelineRangePreset', 'event.target.dataset.value']
4547
4086
  }, {
4548
4087
  name: HandleCloseDetails,
4549
4088
  params: ['handleCloseDetails']
4089
+ }, {
4090
+ name: HandleClickRefresh,
4091
+ params: ['handleClickRefresh']
4092
+ }, {
4093
+ name: HandleTableKeyDown,
4094
+ params: ['handleTableKeyDown', 'event.key']
4550
4095
  }, {
4551
4096
  name: HandleSashPointerDown,
4552
4097
  params: ['handleSashPointerDown', ClientX, ClientY],
@@ -4602,28 +4147,20 @@ const saveState = state => {
4602
4147
  const {
4603
4148
  eventCategoryFilter,
4604
4149
  filterValue,
4605
- height,
4150
+ selectedDetailTab,
4606
4151
  selectedEventId,
4607
4152
  sessionId,
4608
- tableWidth,
4609
4153
  timelineEndSeconds,
4610
- timelineStartSeconds,
4611
- width,
4612
- x,
4613
- y
4154
+ timelineStartSeconds
4614
4155
  } = state;
4615
4156
  return {
4616
4157
  eventCategoryFilter,
4617
4158
  filterValue,
4618
- height,
4159
+ selectedDetailTab,
4619
4160
  selectedEventId,
4620
4161
  sessionId,
4621
- tableWidth,
4622
4162
  timelineEndSeconds,
4623
- timelineStartSeconds,
4624
- width,
4625
- x,
4626
- y
4163
+ timelineStartSeconds
4627
4164
  };
4628
4165
  };
4629
4166
 
@@ -4672,9 +4209,12 @@ const setSessionId = async (state, sessionId) => {
4672
4209
  };
4673
4210
 
4674
4211
  const commandMap = {
4212
+ 'ChatDebug.appendStoredEventForTest': wrapCommand(appendStoredEventForTest),
4675
4213
  'ChatDebug.create': create,
4676
4214
  'ChatDebug.diff2': diff2,
4677
4215
  'ChatDebug.getCommandIds': getCommandIds,
4216
+ 'ChatDebug.getMenuIds': getMenuIds,
4217
+ 'ChatDebug.handleClickRefresh': wrapCommand(handleClickRefresh),
4678
4218
  'ChatDebug.handleCloseDetails': wrapCommand(handleCloseDetails),
4679
4219
  'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
4680
4220
  'ChatDebug.handleDetailTab': wrapCommand(handleDetailTab),