@agent-native/core 0.91.1 → 0.91.2
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/blueprints/action/crud.md +1 -1
- package/blueprints/channel/discord.md +1 -1
- package/blueprints/provider/stripe.md +1 -1
- package/blueprints/sandbox/docker.md +1 -1
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/blueprints/action/crud.md +1 -1
- package/corpus/core/blueprints/channel/discord.md +1 -1
- package/corpus/core/blueprints/provider/stripe.md +1 -1
- package/corpus/core/blueprints/sandbox/docker.md +1 -1
- package/corpus/core/package.json +6 -5
- package/corpus/core/src/agent/run-manager.ts +23 -2
- package/corpus/core/src/agent/run-store.ts +2 -2
- package/corpus/core/src/cli/add.ts +1 -1
- package/corpus/core/src/cli/create.ts +8 -3
- package/corpus/core/src/cli/index.ts +5 -4
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +7 -0
- package/corpus/core/src/client/session-replay.ts +97 -3
- package/corpus/core/src/jobs/scheduler.ts +30 -1
- package/corpus/core/src/localization/default-messages.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/default/package.json +2 -2
- package/corpus/core/src/templates/headless/package.json +3 -3
- package/corpus/core/src/templates/workspace-core/package.json +6 -6
- package/corpus/core/src/templates/workspace-root/package.json +2 -2
- package/corpus/core/src/triggers/dispatcher.ts +30 -2
- package/corpus/core/src/vite/client.ts +96 -1
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +21 -2
- package/corpus/templates/analytics/app/global.css +26 -10
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +25 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +548 -237
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +285 -294
- package/corpus/templates/analytics/changelog/2026-07-08-console-details-expand-inline-under-each-row-and-the-event-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-clamps-ultra-wide-viewports-while-keeping-the.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-keeps-a-usable-stage-when-dev-tools-is-open-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-resumes-after-scrubbing-and-expands-console-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replays-wait-for-full-load-keep-a-normal-viewport-an.md +6 -0
- package/corpus/templates/analytics/package.json +2 -2
- package/corpus/templates/assets/package.json +2 -2
- package/corpus/templates/brain/package.json +2 -2
- package/corpus/templates/calendar/AGENTS.md +10 -0
- package/corpus/templates/calendar/actions/create-event.ts +5 -1
- package/corpus/templates/calendar/actions/event-action-helpers.ts +41 -0
- package/corpus/templates/calendar/actions/get-attendee-timezones.ts +28 -0
- package/corpus/templates/calendar/actions/set-attendee-timezone.ts +68 -0
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +150 -11
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +36 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +32 -0
- package/corpus/templates/calendar/app/hooks/use-attendee-timezones.ts +24 -0
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/app/lib/attendee-local-time.ts +122 -0
- package/corpus/templates/calendar/changelog/2026-07-08-event-details-now-support-extension-widgets-and-you-can-see-.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-08-when-you-invite-guests-to-a-new-event-you-now-appear-in.md +6 -0
- package/corpus/templates/calendar/package.json +2 -2
- package/corpus/templates/calendar/server/handlers/events.ts +5 -1
- package/corpus/templates/calendar/shared/api.ts +6 -0
- package/corpus/templates/chat/package.json +2 -2
- package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +6 -2
- package/corpus/templates/clips/actions/create-meeting.ts +8 -3
- package/corpus/templates/clips/actions/list-meetings.ts +31 -3
- package/corpus/templates/clips/changelog/2026-07-08-after-finishing-a-desktop-recording-reopening-clips-restor.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-clips-now-pops-up-to-take-notes-when-you-join-an-adhoc-zoom-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-desktop-clip-recordings-are-louder-after-capture-mic-only.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-reminders-now-appear-1-minute-before-start-stay-unti.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-the-desktop-meetings-panel-has-room-for-its-drop-shadow-and-.md +6 -0
- package/corpus/templates/clips/chrome-extension/package.json +2 -2
- package/corpus/templates/clips/desktop/package.json +2 -2
- package/corpus/templates/clips/desktop/src/app.tsx +91 -34
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +15 -5
- package/corpus/templates/clips/desktop/src/lib/meeting-notification-timing.ts +83 -0
- package/corpus/templates/clips/desktop/src/lib/native-recording-warm.ts +21 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +98 -20
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +174 -50
- package/corpus/templates/clips/desktop/src/styles.css +128 -53
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +364 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +5 -0
- package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +91 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +69 -19
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +36 -1
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -10
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +1 -24
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +36 -1
- package/corpus/templates/clips/package.json +2 -2
- package/corpus/templates/content/actions/_content-database-personal-view.ts +80 -0
- package/corpus/templates/content/actions/get-content-database-personal-view.ts +27 -0
- package/corpus/templates/content/actions/update-content-database-personal-view.ts +31 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +3 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2584 -546
- package/corpus/templates/content/app/components/editor/database/filter-sort.ts +220 -18
- package/corpus/templates/content/app/hooks/use-content-database.ts +32 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +16 -0
- package/corpus/templates/content/app/i18n-data.ts +154 -0
- package/corpus/templates/content/changelog/2026-07-08-database-filters-now-support-notion-style-reset-save-for-eve.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-date-filters-can-now-target-a-between-range.md +6 -0
- package/corpus/templates/content/package.json +2 -2
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +2 -0
- package/corpus/templates/content/shared/api.ts +24 -0
- package/corpus/templates/design/package.json +2 -2
- package/corpus/templates/dispatch/app/i18n/zh-TW.ts +34 -1
- package/corpus/templates/dispatch/app/i18n-data.ts +387 -10
- package/corpus/templates/dispatch/app/routes/automations.tsx +1 -0
- package/corpus/templates/dispatch/changelog/2026-07-08-added-an-automations-page-to-review-pause-and-create.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-08-destinations-now-shows-outbound-delivery-queue-health.md +6 -0
- package/corpus/templates/dispatch/package.json +2 -2
- package/corpus/templates/forms/package.json +2 -2
- package/corpus/templates/macros/package.json +2 -2
- package/corpus/templates/mail/app/hooks/use-emails.ts +56 -44
- package/corpus/templates/mail/app/lib/gmail-mutation-queue.ts +325 -0
- package/corpus/templates/mail/changelog/2026-07-08-rapid-archive-and-mark-read-now-batch-gmail-updates-so-the-i.md +6 -0
- package/corpus/templates/mail/package.json +2 -2
- package/corpus/templates/plan/package.json +2 -2
- package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +46 -29
- package/corpus/templates/slides/app/context/DeckContext.tsx +45 -18
- package/corpus/templates/slides/app/i18n/ar-SA.ts +4 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +4 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +4 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +115 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +22 -13
- package/corpus/templates/slides/changelog/2026-07-08-dropping-an-image-onto-a-slide-and-sending-it-to-the-agent-w.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-undo-works-after-the-agent-edits-a-slide-so-you-can-reverse.md +6 -0
- package/corpus/templates/slides/package.json +2 -2
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +23 -2
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.js +2 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/catalog.json +2 -2
- package/dist/cli/add.js +1 -1
- package/dist/cli/add.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +8 -3
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +5 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +6 -0
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/session-replay.d.ts +8 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +80 -3
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/scheduler.js +26 -1
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +19 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +19 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/templates/default/app/i18n/ar-SA.ts +21 -0
- package/dist/templates/default/app/i18n/de-DE.ts +21 -0
- package/dist/templates/default/app/i18n/en-US.ts +21 -0
- package/dist/templates/default/app/i18n/es-ES.ts +21 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +20 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +21 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +20 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +21 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +20 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/default/package.json +2 -2
- package/dist/templates/headless/package.json +3 -3
- package/dist/templates/workspace-core/package.json +6 -6
- package/dist/templates/workspace-root/package.json +2 -2
- package/dist/triggers/dispatcher.js +27 -2
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +70 -1
- package/dist/vite/client.js.map +1 -1
- package/package.json +7 -6
- package/src/templates/default/app/i18n/ar-SA.ts +21 -0
- package/src/templates/default/app/i18n/de-DE.ts +21 -0
- package/src/templates/default/app/i18n/en-US.ts +21 -0
- package/src/templates/default/app/i18n/es-ES.ts +21 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +20 -0
- package/src/templates/default/app/i18n/ja-JP.ts +21 -0
- package/src/templates/default/app/i18n/ko-KR.ts +20 -0
- package/src/templates/default/app/i18n/pt-BR.ts +21 -0
- package/src/templates/default/app/i18n/zh-CN.ts +20 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/default/package.json +2 -2
- package/src/templates/headless/package.json +3 -3
- package/src/templates/workspace-core/package.json +6 -6
- package/src/templates/workspace-root/package.json +2 -2
|
@@ -52,14 +52,37 @@ function issueDetailPath(issueId: string): string {
|
|
|
52
52
|
/** Pause row auto-follow for a while after the user scrolls the list. */
|
|
53
53
|
const MANUAL_SCROLL_FOLLOW_PAUSE_MS = 4000;
|
|
54
54
|
const DEVTOOLS_ROW_HEIGHT = 34;
|
|
55
|
+
const DEVTOOLS_EXPANDED_ESTIMATE = 220;
|
|
55
56
|
const DEVTOOLS_OVERSCAN_ROWS = 10;
|
|
56
57
|
const DEVTOOLS_MIN_HEIGHT = 180;
|
|
57
58
|
const DEVTOOLS_MAX_HEIGHT = 620;
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Layout offsets for the virtualized Dev Tools list. Expanded rows reserve
|
|
62
|
+
* extra height so details render inline under the selected line without
|
|
63
|
+
* disabling virtualization for the rest of the list.
|
|
64
|
+
*/
|
|
65
|
+
export function buildDevToolsRowOffsets(
|
|
66
|
+
entryCount: number,
|
|
67
|
+
expandedIndex: number,
|
|
68
|
+
): number[] {
|
|
69
|
+
const offsets = new Array<number>(entryCount + 1);
|
|
70
|
+
offsets[0] = 0;
|
|
71
|
+
for (let index = 0; index < entryCount; index += 1) {
|
|
72
|
+
const height =
|
|
73
|
+
index === expandedIndex
|
|
74
|
+
? DEVTOOLS_EXPANDED_ESTIMATE
|
|
75
|
+
: DEVTOOLS_ROW_HEIGHT;
|
|
76
|
+
offsets[index + 1] = offsets[index] + height;
|
|
77
|
+
}
|
|
78
|
+
return offsets;
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
export function SessionDevToolsPanel({
|
|
60
82
|
diagnostics,
|
|
61
83
|
currentTime,
|
|
62
84
|
height,
|
|
85
|
+
maxHeight = DEVTOOLS_MAX_HEIGHT,
|
|
63
86
|
onHeightChange,
|
|
64
87
|
onSeek,
|
|
65
88
|
issueMatches,
|
|
@@ -67,6 +90,7 @@ export function SessionDevToolsPanel({
|
|
|
67
90
|
diagnostics: ReplayDevToolsDiagnostics;
|
|
68
91
|
currentTime: number;
|
|
69
92
|
height: number;
|
|
93
|
+
maxHeight?: number;
|
|
70
94
|
onHeightChange: (height: number) => void;
|
|
71
95
|
onSeek: (ms: number) => void;
|
|
72
96
|
/** Resolved error issues by console entry id, for cross-linking to Errors. */
|
|
@@ -105,11 +129,6 @@ export function SessionDevToolsPanel({
|
|
|
105
129
|
?.id ?? null)
|
|
106
130
|
: null;
|
|
107
131
|
|
|
108
|
-
const selectedConsole =
|
|
109
|
-
filteredConsole.find((entry) => entry.id === selectedConsoleId) ?? null;
|
|
110
|
-
const selectedNetwork =
|
|
111
|
-
filteredNetwork.find((entry) => entry.id === selectedNetworkId) ?? null;
|
|
112
|
-
|
|
113
132
|
useEffect(() => {
|
|
114
133
|
if (
|
|
115
134
|
selectedConsoleId &&
|
|
@@ -148,9 +167,13 @@ export function SessionDevToolsPanel({
|
|
|
148
167
|
return (
|
|
149
168
|
<div
|
|
150
169
|
className="analytics-session-devtools relative flex min-h-0 shrink-0 flex-col border-t bg-background"
|
|
151
|
-
style={{ height }}
|
|
170
|
+
style={{ height: Math.min(height, maxHeight) }}
|
|
152
171
|
>
|
|
153
|
-
<DevToolsResizeHandle
|
|
172
|
+
<DevToolsResizeHandle
|
|
173
|
+
height={Math.min(height, maxHeight)}
|
|
174
|
+
maxHeight={maxHeight}
|
|
175
|
+
onHeightChange={onHeightChange}
|
|
176
|
+
/>
|
|
154
177
|
<Tabs
|
|
155
178
|
value={tab}
|
|
156
179
|
onValueChange={(value) => setTab(value as "console" | "network")}
|
|
@@ -230,16 +253,17 @@ export function SessionDevToolsPanel({
|
|
|
230
253
|
<VirtualizedDevToolsList
|
|
231
254
|
entries={filteredConsole}
|
|
232
255
|
activeEntryId={activeConsoleId}
|
|
256
|
+
expandedEntryId={selectedConsoleId}
|
|
233
257
|
emptyMessage={
|
|
234
258
|
diagnostics.console.length
|
|
235
259
|
? t("sessions.devtoolsNoConsoleMatches")
|
|
236
260
|
: t("sessions.devtoolsNoConsole")
|
|
237
261
|
}
|
|
238
|
-
renderRow={(entry) => (
|
|
262
|
+
renderRow={(entry, expanded) => (
|
|
239
263
|
<ConsoleRow
|
|
240
264
|
entry={entry}
|
|
241
265
|
active={entry.id === activeConsoleId}
|
|
242
|
-
selected={
|
|
266
|
+
selected={expanded}
|
|
243
267
|
issueMatch={issueMatches?.get(entry.id) ?? null}
|
|
244
268
|
onSelect={() =>
|
|
245
269
|
setSelectedConsoleId((current) =>
|
|
@@ -250,13 +274,6 @@ export function SessionDevToolsPanel({
|
|
|
250
274
|
/>
|
|
251
275
|
)}
|
|
252
276
|
/>
|
|
253
|
-
{selectedConsole ? (
|
|
254
|
-
<ConsoleDetailPane
|
|
255
|
-
entry={selectedConsole}
|
|
256
|
-
issueMatch={issueMatches?.get(selectedConsole.id) ?? null}
|
|
257
|
-
onSeek={onSeek}
|
|
258
|
-
/>
|
|
259
|
-
) : null}
|
|
260
277
|
</TabsContent>
|
|
261
278
|
|
|
262
279
|
<TabsContent
|
|
@@ -302,16 +319,17 @@ export function SessionDevToolsPanel({
|
|
|
302
319
|
<VirtualizedDevToolsList
|
|
303
320
|
entries={filteredNetwork}
|
|
304
321
|
activeEntryId={activeNetworkId}
|
|
322
|
+
expandedEntryId={selectedNetworkId}
|
|
305
323
|
emptyMessage={
|
|
306
324
|
diagnostics.network.length
|
|
307
325
|
? t("sessions.devtoolsNoNetworkMatches")
|
|
308
326
|
: t("sessions.devtoolsNoNetwork")
|
|
309
327
|
}
|
|
310
|
-
renderRow={(entry) => (
|
|
328
|
+
renderRow={(entry, expanded) => (
|
|
311
329
|
<NetworkRow
|
|
312
330
|
entry={entry}
|
|
313
331
|
active={entry.id === activeNetworkId}
|
|
314
|
-
selected={
|
|
332
|
+
selected={expanded}
|
|
315
333
|
onSelect={() =>
|
|
316
334
|
setSelectedNetworkId((current) =>
|
|
317
335
|
current === entry.id ? null : entry.id,
|
|
@@ -321,9 +339,6 @@ export function SessionDevToolsPanel({
|
|
|
321
339
|
/>
|
|
322
340
|
)}
|
|
323
341
|
/>
|
|
324
|
-
{selectedNetwork ? (
|
|
325
|
-
<NetworkDetailPane entry={selectedNetwork} onSeek={onSeek} />
|
|
326
|
-
) : null}
|
|
327
342
|
</TabsContent>
|
|
328
343
|
</Tabs>
|
|
329
344
|
</div>
|
|
@@ -332,12 +347,15 @@ export function SessionDevToolsPanel({
|
|
|
332
347
|
|
|
333
348
|
function DevToolsResizeHandle({
|
|
334
349
|
height,
|
|
350
|
+
maxHeight,
|
|
335
351
|
onHeightChange,
|
|
336
352
|
}: {
|
|
337
353
|
height: number;
|
|
354
|
+
maxHeight: number;
|
|
338
355
|
onHeightChange: (height: number) => void;
|
|
339
356
|
}) {
|
|
340
357
|
const t = useT();
|
|
358
|
+
const cappedMax = Math.max(DEVTOOLS_MIN_HEIGHT, maxHeight);
|
|
341
359
|
|
|
342
360
|
function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>) {
|
|
343
361
|
event.preventDefault();
|
|
@@ -348,8 +366,8 @@ function DevToolsResizeHandle({
|
|
|
348
366
|
onHeightChange(
|
|
349
367
|
clamp(
|
|
350
368
|
startHeight - (moveEvent.clientY - startY),
|
|
351
|
-
DEVTOOLS_MIN_HEIGHT,
|
|
352
|
-
|
|
369
|
+
Math.min(DEVTOOLS_MIN_HEIGHT, cappedMax),
|
|
370
|
+
cappedMax,
|
|
353
371
|
),
|
|
354
372
|
);
|
|
355
373
|
}
|
|
@@ -368,8 +386,8 @@ function DevToolsResizeHandle({
|
|
|
368
386
|
role="separator"
|
|
369
387
|
aria-label={t("sessions.devtoolsResize")}
|
|
370
388
|
aria-orientation="horizontal"
|
|
371
|
-
aria-valuemin={DEVTOOLS_MIN_HEIGHT}
|
|
372
|
-
aria-valuemax={
|
|
389
|
+
aria-valuemin={Math.min(DEVTOOLS_MIN_HEIGHT, cappedMax)}
|
|
390
|
+
aria-valuemax={cappedMax}
|
|
373
391
|
aria-valuenow={Math.round(height)}
|
|
374
392
|
className="absolute inset-x-0 -top-1 z-10 flex h-2 cursor-row-resize items-center justify-center"
|
|
375
393
|
onPointerDown={handlePointerDown}
|
|
@@ -382,13 +400,15 @@ function DevToolsResizeHandle({
|
|
|
382
400
|
function VirtualizedDevToolsList<T extends { id: string }>({
|
|
383
401
|
entries,
|
|
384
402
|
activeEntryId,
|
|
403
|
+
expandedEntryId,
|
|
385
404
|
emptyMessage,
|
|
386
405
|
renderRow,
|
|
387
406
|
}: {
|
|
388
407
|
entries: T[];
|
|
389
408
|
activeEntryId: string | null;
|
|
409
|
+
expandedEntryId: string | null;
|
|
390
410
|
emptyMessage: string;
|
|
391
|
-
renderRow: (entry: T) => ReactNode;
|
|
411
|
+
renderRow: (entry: T, expanded: boolean) => ReactNode;
|
|
392
412
|
}) {
|
|
393
413
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
394
414
|
const lastManualScrollAtRef = useRef(0);
|
|
@@ -398,6 +418,16 @@ function VirtualizedDevToolsList<T extends { id: string }>({
|
|
|
398
418
|
const activeIndex = activeEntryId
|
|
399
419
|
? entries.findIndex((entry) => entry.id === activeEntryId)
|
|
400
420
|
: -1;
|
|
421
|
+
const expandedIndex = expandedEntryId
|
|
422
|
+
? entries.findIndex((entry) => entry.id === expandedEntryId)
|
|
423
|
+
: -1;
|
|
424
|
+
|
|
425
|
+
const rowOffsets = useMemo(
|
|
426
|
+
() => buildDevToolsRowOffsets(entries.length, expandedIndex),
|
|
427
|
+
[entries.length, expandedIndex],
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const totalHeight = rowOffsets[entries.length] ?? 0;
|
|
401
431
|
|
|
402
432
|
useEffect(() => {
|
|
403
433
|
const el = containerRef.current;
|
|
@@ -419,15 +449,16 @@ function VirtualizedDevToolsList<T extends { id: string }>({
|
|
|
419
449
|
}
|
|
420
450
|
const el = containerRef.current;
|
|
421
451
|
if (!el) return;
|
|
422
|
-
const rowTop = activeIndex
|
|
423
|
-
const rowBottom =
|
|
452
|
+
const rowTop = rowOffsets[activeIndex] ?? 0;
|
|
453
|
+
const rowBottom =
|
|
454
|
+
rowOffsets[activeIndex + 1] ?? rowTop + DEVTOOLS_ROW_HEIGHT;
|
|
424
455
|
if (rowTop >= el.scrollTop && rowBottom <= el.scrollTop + el.clientHeight) {
|
|
425
456
|
return;
|
|
426
457
|
}
|
|
427
458
|
el.scrollTo({
|
|
428
459
|
top: Math.max(0, rowTop - el.clientHeight / 2 + DEVTOOLS_ROW_HEIGHT),
|
|
429
460
|
});
|
|
430
|
-
}, [activeIndex, entries.length]);
|
|
461
|
+
}, [activeIndex, entries.length, rowOffsets]);
|
|
431
462
|
|
|
432
463
|
const markManualScroll = () => {
|
|
433
464
|
lastManualScrollAtRef.current = Date.now();
|
|
@@ -442,14 +473,24 @@ function VirtualizedDevToolsList<T extends { id: string }>({
|
|
|
442
473
|
}
|
|
443
474
|
|
|
444
475
|
const measuredHeight = viewportHeight || 240;
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
)
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
476
|
+
let startIndex = 0;
|
|
477
|
+
while (
|
|
478
|
+
startIndex < entries.length &&
|
|
479
|
+
(rowOffsets[startIndex + 1] ?? 0) < scrollTop
|
|
480
|
+
) {
|
|
481
|
+
startIndex += 1;
|
|
482
|
+
}
|
|
483
|
+
startIndex = clamp(startIndex - DEVTOOLS_OVERSCAN_ROWS, 0, entries.length);
|
|
484
|
+
|
|
485
|
+
let endIndex = startIndex;
|
|
486
|
+
while (
|
|
487
|
+
endIndex < entries.length &&
|
|
488
|
+
(rowOffsets[endIndex] ?? 0) < scrollTop + measuredHeight
|
|
489
|
+
) {
|
|
490
|
+
endIndex += 1;
|
|
491
|
+
}
|
|
492
|
+
endIndex = clamp(
|
|
493
|
+
endIndex + DEVTOOLS_OVERSCAN_ROWS,
|
|
453
494
|
startIndex,
|
|
454
495
|
entries.length,
|
|
455
496
|
);
|
|
@@ -464,22 +505,26 @@ function VirtualizedDevToolsList<T extends { id: string }>({
|
|
|
464
505
|
onPointerDown={markManualScroll}
|
|
465
506
|
onTouchMove={markManualScroll}
|
|
466
507
|
>
|
|
467
|
-
<div
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
508
|
+
<div className="relative" style={{ height: totalHeight }}>
|
|
509
|
+
{visibleEntries.map((entry, offset) => {
|
|
510
|
+
const index = startIndex + offset;
|
|
511
|
+
const expanded = entry.id === expandedEntryId;
|
|
512
|
+
const top = rowOffsets[index] ?? 0;
|
|
513
|
+
const height =
|
|
514
|
+
(rowOffsets[index + 1] ?? top + DEVTOOLS_ROW_HEIGHT) - top;
|
|
515
|
+
return (
|
|
516
|
+
<div
|
|
517
|
+
key={entry.id}
|
|
518
|
+
className="absolute inset-x-0"
|
|
519
|
+
style={{
|
|
520
|
+
minHeight: height,
|
|
521
|
+
top,
|
|
522
|
+
}}
|
|
523
|
+
>
|
|
524
|
+
{renderRow(entry, expanded)}
|
|
525
|
+
</div>
|
|
526
|
+
);
|
|
527
|
+
})}
|
|
483
528
|
</div>
|
|
484
529
|
</div>
|
|
485
530
|
);
|
|
@@ -617,66 +662,104 @@ function ConsoleRow({
|
|
|
617
662
|
onSelect: () => void;
|
|
618
663
|
onSeek: (ms: number) => void;
|
|
619
664
|
}) {
|
|
665
|
+
const t = useT();
|
|
620
666
|
const bucket = consoleLevelBucket(entry.level);
|
|
621
667
|
|
|
622
668
|
return (
|
|
623
669
|
<div
|
|
624
670
|
data-entry-id={entry.id}
|
|
625
671
|
className={cn(
|
|
626
|
-
"group
|
|
627
|
-
active && "bg-
|
|
628
|
-
selected && "bg-muted/
|
|
672
|
+
"group border-b transition-colors hover:bg-muted/50",
|
|
673
|
+
active && "bg-primary/[0.06] dark:bg-primary/[0.09]",
|
|
674
|
+
selected && "bg-muted/40",
|
|
629
675
|
)}
|
|
630
676
|
>
|
|
631
|
-
<
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
<span className="w-10 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
638
|
-
{formatOffsetClock(entry.offsetMs)}
|
|
639
|
-
</span>
|
|
640
|
-
<span
|
|
641
|
-
className={cn(
|
|
642
|
-
"h-2 w-2 shrink-0 rounded-full",
|
|
643
|
-
bucket === "error" && "bg-red-500",
|
|
644
|
-
bucket === "warn" && "bg-amber-500",
|
|
645
|
-
bucket === "info" && "bg-sky-500",
|
|
646
|
-
bucket === "log" && "bg-muted-foreground/50",
|
|
647
|
-
)}
|
|
648
|
-
aria-hidden
|
|
649
|
-
/>
|
|
650
|
-
<span
|
|
651
|
-
className={cn(
|
|
652
|
-
"min-w-0 flex-1 truncate font-mono text-xs",
|
|
653
|
-
bucket === "error" && "text-red-600 dark:text-red-400",
|
|
654
|
-
bucket === "warn" && "text-amber-600 dark:text-amber-400",
|
|
655
|
-
bucket !== "error" && bucket !== "warn" && "text-foreground/80",
|
|
656
|
-
)}
|
|
657
|
-
title={entry.message}
|
|
677
|
+
<div className="flex h-[34px] items-center gap-2 px-3">
|
|
678
|
+
<button
|
|
679
|
+
type="button"
|
|
680
|
+
className="flex min-w-0 flex-1 items-center gap-2 text-left"
|
|
681
|
+
aria-expanded={selected}
|
|
682
|
+
onClick={onSelect}
|
|
658
683
|
>
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
{entry.repeat > 1 ? (
|
|
662
|
-
<span className="inline-flex shrink-0 items-center rounded-full bg-muted px-1.5 font-mono text-[10px] text-muted-foreground">
|
|
663
|
-
x{entry.repeat}
|
|
684
|
+
<span className="w-10 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
685
|
+
{formatOffsetClock(entry.offsetMs)}
|
|
664
686
|
</span>
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
687
|
+
<span
|
|
688
|
+
className={cn(
|
|
689
|
+
"h-2 w-2 shrink-0 rounded-full",
|
|
690
|
+
bucket === "error" && "bg-red-500",
|
|
691
|
+
bucket === "warn" && "bg-amber-500",
|
|
692
|
+
bucket === "info" && "bg-sky-500",
|
|
693
|
+
bucket === "log" && "bg-muted-foreground/50",
|
|
694
|
+
)}
|
|
695
|
+
aria-hidden
|
|
696
|
+
/>
|
|
697
|
+
<span
|
|
698
|
+
className={cn(
|
|
699
|
+
"min-w-0 flex-1 truncate font-mono text-xs",
|
|
700
|
+
bucket === "error" && "text-red-600 dark:text-red-400",
|
|
701
|
+
bucket === "warn" && "text-amber-600 dark:text-amber-400",
|
|
702
|
+
bucket !== "error" && bucket !== "warn" && "text-foreground/80",
|
|
703
|
+
)}
|
|
704
|
+
title={entry.message}
|
|
705
|
+
>
|
|
706
|
+
{entry.message || entry.level}
|
|
669
707
|
</span>
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
708
|
+
{entry.repeat > 1 ? (
|
|
709
|
+
<span className="inline-flex shrink-0 items-center rounded-full bg-muted px-1.5 font-mono text-[10px] text-muted-foreground">
|
|
710
|
+
x{entry.repeat}
|
|
711
|
+
</span>
|
|
712
|
+
) : null}
|
|
713
|
+
{entry.source !== "console" ? (
|
|
714
|
+
<span className="hidden shrink-0 rounded border px-1 font-mono text-[10px] text-muted-foreground sm:inline-flex">
|
|
715
|
+
{entry.source}
|
|
716
|
+
</span>
|
|
717
|
+
) : null}
|
|
718
|
+
<IconChevronRight
|
|
719
|
+
className={cn(
|
|
720
|
+
"h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform rtl:-scale-x-100",
|
|
721
|
+
selected && "rotate-90 rtl:scale-x-100",
|
|
722
|
+
)}
|
|
723
|
+
/>
|
|
724
|
+
</button>
|
|
725
|
+
{issueMatch ? <ViewIssueLink issueId={issueMatch.issueId} /> : null}
|
|
726
|
+
<JumpToButton offsetMs={entry.offsetMs} onSeek={onSeek} />
|
|
727
|
+
</div>
|
|
728
|
+
{selected ? (
|
|
729
|
+
<div className="space-y-2 border-t border-border/60 bg-muted/20 px-3 py-2 ps-[3.25rem]">
|
|
730
|
+
<DetailField label={t("sessions.devtoolsMessage")}>
|
|
731
|
+
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-foreground/85">
|
|
732
|
+
{entry.message || entry.level}
|
|
733
|
+
</pre>
|
|
734
|
+
</DetailField>
|
|
735
|
+
{entry.url ? (
|
|
736
|
+
<DetailField label={t("sessions.url")}>
|
|
737
|
+
<p className="break-all font-mono text-[11px] text-muted-foreground">
|
|
738
|
+
{entry.url}
|
|
739
|
+
</p>
|
|
740
|
+
</DetailField>
|
|
741
|
+
) : null}
|
|
742
|
+
{entry.args.length ? (
|
|
743
|
+
<DetailField label={t("sessions.devtoolsArgs")}>
|
|
744
|
+
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
745
|
+
{entry.args.join("\n")}
|
|
746
|
+
</pre>
|
|
747
|
+
</DetailField>
|
|
748
|
+
) : null}
|
|
749
|
+
{entry.stack ? (
|
|
750
|
+
<DetailField label={t("sessions.devtoolsStack")}>
|
|
751
|
+
<pre className="max-h-40 overflow-auto whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
752
|
+
{entry.stack}
|
|
753
|
+
</pre>
|
|
754
|
+
</DetailField>
|
|
755
|
+
) : null}
|
|
756
|
+
{issueMatch ? (
|
|
757
|
+
<div className="pt-1">
|
|
758
|
+
<ViewIssueLink issueId={issueMatch.issueId} />
|
|
759
|
+
</div>
|
|
760
|
+
) : null}
|
|
761
|
+
</div>
|
|
762
|
+
) : null}
|
|
680
763
|
</div>
|
|
681
764
|
);
|
|
682
765
|
}
|
|
@@ -701,206 +784,114 @@ function NetworkRow({
|
|
|
701
784
|
<div
|
|
702
785
|
data-entry-id={entry.id}
|
|
703
786
|
className={cn(
|
|
704
|
-
"group
|
|
705
|
-
active && "bg-
|
|
706
|
-
selected && "bg-muted/
|
|
787
|
+
"group border-b transition-colors hover:bg-muted/50",
|
|
788
|
+
active && "bg-primary/[0.06] dark:bg-primary/[0.09]",
|
|
789
|
+
selected && "bg-muted/40",
|
|
707
790
|
)}
|
|
708
791
|
>
|
|
709
|
-
<
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
<span className="w-10 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
716
|
-
{formatOffsetClock(entry.offsetMs)}
|
|
717
|
-
</span>
|
|
718
|
-
<span
|
|
719
|
-
className={cn(
|
|
720
|
-
"w-12 shrink-0 font-mono text-[11px] font-semibold",
|
|
721
|
-
entry.failed
|
|
722
|
-
? "text-red-600 dark:text-red-400"
|
|
723
|
-
: "text-muted-foreground",
|
|
724
|
-
)}
|
|
725
|
-
>
|
|
726
|
-
{entry.status > 0 ? entry.status : t("sessions.devtoolsFailedStatus")}
|
|
727
|
-
</span>
|
|
728
|
-
<span className="w-12 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
729
|
-
{entry.method}
|
|
730
|
-
</span>
|
|
731
|
-
<span className="hidden w-10 shrink-0 font-mono text-[10px] uppercase text-muted-foreground/70 sm:inline">
|
|
732
|
-
{entry.api === "xhr" ? "XHR" : "fetch"}
|
|
733
|
-
</span>
|
|
734
|
-
<span
|
|
735
|
-
className="min-w-0 flex-1 truncate font-mono text-xs text-foreground/80"
|
|
736
|
-
title={entry.url}
|
|
792
|
+
<div className="flex h-[34px] items-center gap-2 px-3">
|
|
793
|
+
<button
|
|
794
|
+
type="button"
|
|
795
|
+
className="flex min-w-0 flex-1 items-center gap-2 text-left"
|
|
796
|
+
aria-expanded={selected}
|
|
797
|
+
onClick={onSelect}
|
|
737
798
|
>
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
799
|
+
<span className="w-10 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
800
|
+
{formatOffsetClock(entry.offsetMs)}
|
|
801
|
+
</span>
|
|
741
802
|
<span
|
|
742
|
-
className=
|
|
743
|
-
|
|
803
|
+
className={cn(
|
|
804
|
+
"w-12 shrink-0 font-mono text-[11px] font-semibold",
|
|
805
|
+
entry.failed
|
|
806
|
+
? "text-red-600 dark:text-red-400"
|
|
807
|
+
: "text-muted-foreground",
|
|
808
|
+
)}
|
|
744
809
|
>
|
|
745
|
-
{entry.
|
|
810
|
+
{entry.status > 0
|
|
811
|
+
? entry.status
|
|
812
|
+
: t("sessions.devtoolsFailedStatus")}
|
|
746
813
|
</span>
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
selected && "rotate-90 rtl:scale-x-100",
|
|
757
|
-
)}
|
|
758
|
-
/>
|
|
759
|
-
</button>
|
|
760
|
-
<JumpToButton offsetMs={entry.offsetMs} onSeek={onSeek} />
|
|
761
|
-
</div>
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
function ConsoleDetailPane({
|
|
766
|
-
entry,
|
|
767
|
-
issueMatch,
|
|
768
|
-
onSeek,
|
|
769
|
-
}: {
|
|
770
|
-
entry: ReplayConsoleEntry;
|
|
771
|
-
issueMatch: SessionIssueMatch | null;
|
|
772
|
-
onSeek: (ms: number) => void;
|
|
773
|
-
}) {
|
|
774
|
-
const t = useT();
|
|
775
|
-
return (
|
|
776
|
-
<DevToolsDetailPane
|
|
777
|
-
title={`${entry.level} at ${formatOffsetClock(entry.offsetMs)}`}
|
|
778
|
-
action={
|
|
779
|
-
issueMatch ? <ViewIssueLink issueId={issueMatch.issueId} /> : null
|
|
780
|
-
}
|
|
781
|
-
onSeek={() => onSeek(entry.offsetMs)}
|
|
782
|
-
>
|
|
783
|
-
<DetailField label={t("sessions.devtoolsMessage")}>
|
|
784
|
-
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-foreground/85">
|
|
785
|
-
{entry.message || entry.level}
|
|
786
|
-
</pre>
|
|
787
|
-
</DetailField>
|
|
788
|
-
{entry.url ? (
|
|
789
|
-
<DetailField label={t("sessions.url")}>
|
|
790
|
-
<p className="break-all font-mono text-[11px] text-muted-foreground">
|
|
791
|
-
{entry.url}
|
|
792
|
-
</p>
|
|
793
|
-
</DetailField>
|
|
794
|
-
) : null}
|
|
795
|
-
{entry.args.length ? (
|
|
796
|
-
<DetailField label={t("sessions.devtoolsArgs")}>
|
|
797
|
-
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
798
|
-
{entry.args.join("\n")}
|
|
799
|
-
</pre>
|
|
800
|
-
</DetailField>
|
|
801
|
-
) : null}
|
|
802
|
-
{entry.stack ? (
|
|
803
|
-
<DetailField label={t("sessions.devtoolsStack")}>
|
|
804
|
-
<pre className="max-h-32 overflow-auto whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
805
|
-
{entry.stack}
|
|
806
|
-
</pre>
|
|
807
|
-
</DetailField>
|
|
808
|
-
) : null}
|
|
809
|
-
</DevToolsDetailPane>
|
|
810
|
-
);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
function NetworkDetailPane({
|
|
814
|
-
entry,
|
|
815
|
-
onSeek,
|
|
816
|
-
}: {
|
|
817
|
-
entry: ReplayNetworkEntry;
|
|
818
|
-
onSeek: (ms: number) => void;
|
|
819
|
-
}) {
|
|
820
|
-
const t = useT();
|
|
821
|
-
return (
|
|
822
|
-
<DevToolsDetailPane
|
|
823
|
-
title={`${entry.method} ${entry.status > 0 ? entry.status : t("sessions.devtoolsFailedStatus")}`}
|
|
824
|
-
onSeek={() => onSeek(entry.offsetMs)}
|
|
825
|
-
>
|
|
826
|
-
<div className="grid gap-2 sm:grid-cols-2">
|
|
827
|
-
<DetailValue
|
|
828
|
-
label={t("sessions.time")}
|
|
829
|
-
value={formatOffsetClock(entry.offsetMs)}
|
|
830
|
-
/>
|
|
831
|
-
<DetailValue
|
|
832
|
-
label="API"
|
|
833
|
-
value={entry.api === "xhr" ? "XHR" : "fetch"}
|
|
834
|
-
/>
|
|
835
|
-
<DetailValue
|
|
836
|
-
label="Status"
|
|
837
|
-
value={
|
|
838
|
-
entry.status > 0
|
|
839
|
-
? String(entry.status)
|
|
840
|
-
: t("sessions.devtoolsFailedStatus")
|
|
841
|
-
}
|
|
842
|
-
/>
|
|
843
|
-
<DetailValue
|
|
844
|
-
label="Duration"
|
|
845
|
-
value={t("sessions.devtoolsDurationMs", {
|
|
846
|
-
ms: String(entry.durationMs),
|
|
847
|
-
})}
|
|
848
|
-
/>
|
|
849
|
-
</div>
|
|
850
|
-
<DetailField label={t("sessions.url")}>
|
|
851
|
-
<p className="break-all font-mono text-[11px] text-muted-foreground">
|
|
852
|
-
{entry.url}
|
|
853
|
-
</p>
|
|
854
|
-
</DetailField>
|
|
855
|
-
{entry.error ? (
|
|
856
|
-
<DetailField label="Error">
|
|
857
|
-
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-red-600 dark:text-red-400">
|
|
858
|
-
{entry.error}
|
|
859
|
-
</pre>
|
|
860
|
-
</DetailField>
|
|
861
|
-
) : null}
|
|
862
|
-
{entry.responseBody ? (
|
|
863
|
-
<DetailField label={t("sessions.devtoolsResponseBody")}>
|
|
864
|
-
<pre className="max-h-32 overflow-auto whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
865
|
-
{entry.responseBody}
|
|
866
|
-
</pre>
|
|
867
|
-
</DetailField>
|
|
868
|
-
) : null}
|
|
869
|
-
</DevToolsDetailPane>
|
|
870
|
-
);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
function DevToolsDetailPane({
|
|
874
|
-
title,
|
|
875
|
-
onSeek,
|
|
876
|
-
action,
|
|
877
|
-
children,
|
|
878
|
-
}: {
|
|
879
|
-
title: string;
|
|
880
|
-
onSeek: () => void;
|
|
881
|
-
action?: ReactNode;
|
|
882
|
-
children: ReactNode;
|
|
883
|
-
}) {
|
|
884
|
-
const t = useT();
|
|
885
|
-
return (
|
|
886
|
-
<div className="max-h-44 shrink-0 overflow-auto border-t bg-muted/25 px-3 py-2">
|
|
887
|
-
<div className="mb-2 flex items-center justify-between gap-3">
|
|
888
|
-
<p className="truncate text-xs font-semibold text-foreground">
|
|
889
|
-
{title}
|
|
890
|
-
</p>
|
|
891
|
-
<div className="flex shrink-0 items-center gap-1.5">
|
|
892
|
-
{action}
|
|
893
|
-
<button
|
|
894
|
-
type="button"
|
|
895
|
-
className="inline-flex shrink-0 items-center gap-1 rounded border px-1.5 py-0.5 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
896
|
-
onClick={onSeek}
|
|
814
|
+
<span className="w-12 shrink-0 font-mono text-[11px] text-muted-foreground">
|
|
815
|
+
{entry.method}
|
|
816
|
+
</span>
|
|
817
|
+
<span className="hidden w-10 shrink-0 font-mono text-[10px] uppercase text-muted-foreground/70 sm:inline">
|
|
818
|
+
{entry.api === "xhr" ? "XHR" : "fetch"}
|
|
819
|
+
</span>
|
|
820
|
+
<span
|
|
821
|
+
className="min-w-0 flex-1 truncate font-mono text-xs text-foreground/80"
|
|
822
|
+
title={entry.url}
|
|
897
823
|
>
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
824
|
+
{displayUrl}
|
|
825
|
+
</span>
|
|
826
|
+
{entry.error ? (
|
|
827
|
+
<span
|
|
828
|
+
className="hidden max-w-32 shrink-0 truncate font-mono text-[11px] text-red-600 dark:text-red-400 lg:inline"
|
|
829
|
+
title={entry.error}
|
|
830
|
+
>
|
|
831
|
+
{entry.error}
|
|
832
|
+
</span>
|
|
833
|
+
) : null}
|
|
834
|
+
<span className="w-14 shrink-0 text-end font-mono text-[11px] text-muted-foreground">
|
|
835
|
+
{t("sessions.devtoolsDurationMs", {
|
|
836
|
+
ms: String(entry.durationMs),
|
|
837
|
+
})}
|
|
838
|
+
</span>
|
|
839
|
+
<IconChevronRight
|
|
840
|
+
className={cn(
|
|
841
|
+
"h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform rtl:-scale-x-100",
|
|
842
|
+
selected && "rotate-90 rtl:scale-x-100",
|
|
843
|
+
)}
|
|
844
|
+
/>
|
|
845
|
+
</button>
|
|
846
|
+
<JumpToButton offsetMs={entry.offsetMs} onSeek={onSeek} />
|
|
902
847
|
</div>
|
|
903
|
-
|
|
848
|
+
{selected ? (
|
|
849
|
+
<div className="space-y-2 border-t border-border/60 bg-muted/20 px-3 py-2 ps-[3.25rem]">
|
|
850
|
+
<div className="grid gap-2 sm:grid-cols-2">
|
|
851
|
+
<DetailValue
|
|
852
|
+
label={t("sessions.time")}
|
|
853
|
+
value={formatOffsetClock(entry.offsetMs)}
|
|
854
|
+
/>
|
|
855
|
+
<DetailValue
|
|
856
|
+
label="API"
|
|
857
|
+
value={entry.api === "xhr" ? "XHR" : "fetch"}
|
|
858
|
+
/>
|
|
859
|
+
<DetailValue
|
|
860
|
+
label="Status"
|
|
861
|
+
value={
|
|
862
|
+
entry.status > 0
|
|
863
|
+
? String(entry.status)
|
|
864
|
+
: t("sessions.devtoolsFailedStatus")
|
|
865
|
+
}
|
|
866
|
+
/>
|
|
867
|
+
<DetailValue
|
|
868
|
+
label="Duration"
|
|
869
|
+
value={t("sessions.devtoolsDurationMs", {
|
|
870
|
+
ms: String(entry.durationMs),
|
|
871
|
+
})}
|
|
872
|
+
/>
|
|
873
|
+
</div>
|
|
874
|
+
<DetailField label={t("sessions.url")}>
|
|
875
|
+
<p className="break-all font-mono text-[11px] text-muted-foreground">
|
|
876
|
+
{entry.url}
|
|
877
|
+
</p>
|
|
878
|
+
</DetailField>
|
|
879
|
+
{entry.error ? (
|
|
880
|
+
<DetailField label="Error">
|
|
881
|
+
<pre className="whitespace-pre-wrap break-all font-mono text-[11px] text-red-600 dark:text-red-400">
|
|
882
|
+
{entry.error}
|
|
883
|
+
</pre>
|
|
884
|
+
</DetailField>
|
|
885
|
+
) : null}
|
|
886
|
+
{entry.responseBody ? (
|
|
887
|
+
<DetailField label={t("sessions.devtoolsResponseBody")}>
|
|
888
|
+
<pre className="max-h-40 overflow-auto whitespace-pre-wrap break-all font-mono text-[11px] text-muted-foreground">
|
|
889
|
+
{entry.responseBody}
|
|
890
|
+
</pre>
|
|
891
|
+
</DetailField>
|
|
892
|
+
) : null}
|
|
893
|
+
</div>
|
|
894
|
+
) : null}
|
|
904
895
|
</div>
|
|
905
896
|
);
|
|
906
897
|
}
|