@sentry/junior-dashboard 0.264.0 → 0.266.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +2 -5
- package/dist/app.js +119 -35
- package/dist/client.js +145 -136
- package/dist/index.d.ts +0 -1
- package/dist/index.js +119 -35
- package/dist/tailwind.css +1 -1
- package/package.json +5 -4
- package/src/api/schema.ts +0 -1
- package/src/app.ts +5 -20
- package/src/client/App.tsx +29 -31
- package/src/client/api.ts +7 -0
- package/src/client/components/ActorAvatar.tsx +10 -22
- package/src/client/components/BottomSheet.tsx +12 -2
- package/src/client/components/ConnectionBanner.tsx +4 -3
- package/src/client/components/CopyButton.tsx +82 -0
- package/src/client/components/DetailsPanel.tsx +133 -0
- package/src/client/components/Drawer.tsx +15 -24
- package/src/client/components/EmptyTelemetry.tsx +5 -3
- package/src/client/components/FilterBar.tsx +16 -31
- package/src/client/components/ImageAttachment.tsx +49 -63
- package/src/client/components/InlineError.tsx +8 -4
- package/src/client/components/Metric.tsx +33 -23
- package/src/client/components/Notice.tsx +19 -26
- package/src/client/components/PageContentSkeleton.tsx +1 -1
- package/src/client/components/Pagination.tsx +27 -27
- package/src/client/components/ParticipantAvatarStack.tsx +43 -39
- package/src/client/components/ProfileMenu.tsx +27 -93
- package/src/client/components/README.md +103 -78
- package/src/client/components/SearchInput.tsx +51 -41
- package/src/client/components/SegmentedNav.tsx +1 -1
- package/src/client/components/ShimmerText.tsx +2 -6
- package/src/client/components/ThemeSwitcher.tsx +19 -15
- package/src/client/components/VersionDriftBanner.tsx +9 -7
- package/src/client/components/charts/ActivityChart.tsx +173 -288
- package/src/client/components/charts/CacheWrites.tsx +59 -37
- package/src/client/components/charts/InputCacheChart.tsx +137 -131
- package/src/client/components/charts/README.md +4 -4
- package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
- package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
- package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
- package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
- package/src/client/components/layout/DashboardHeader.tsx +44 -90
- package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
- package/src/client/components/layout/VisualViewportShell.tsx +2 -2
- package/src/client/components/ui/accordion.tsx +77 -0
- package/src/client/components/ui/alert-dialog.tsx +89 -0
- package/src/client/components/ui/alert.tsx +64 -0
- package/src/client/components/ui/avatar.tsx +53 -0
- package/src/client/components/ui/button.tsx +86 -0
- package/src/client/components/ui/chart.tsx +74 -0
- package/src/client/components/ui/checkbox.tsx +26 -0
- package/src/client/components/ui/collapsible.tsx +22 -0
- package/src/client/components/ui/dialog.tsx +66 -0
- package/src/client/components/ui/empty.tsx +32 -0
- package/src/client/components/ui/field.tsx +49 -0
- package/src/client/components/ui/input-group.tsx +96 -0
- package/src/client/components/ui/input.tsx +35 -0
- package/src/client/components/ui/native-select.tsx +57 -0
- package/src/client/components/ui/pagination.tsx +60 -0
- package/src/client/components/ui/popover.tsx +67 -0
- package/src/client/components/ui/radio-group.tsx +32 -0
- package/src/client/components/ui/sheet.tsx +13 -3
- package/src/client/components/ui/skeleton.tsx +19 -0
- package/src/client/components/ui/spinner.tsx +21 -0
- package/src/client/components/ui/table.tsx +101 -0
- package/src/client/components/ui/tabs.tsx +75 -0
- package/src/client/components/ui/textarea.tsx +17 -0
- package/src/client/components/ui/toast.tsx +215 -0
- package/src/client/components/ui/toggle-group.tsx +36 -0
- package/src/client/components/ui/toggle.tsx +37 -0
- package/src/client/components/ui/tooltip.tsx +168 -0
- package/src/client/components/ui/trace.tsx +96 -0
- package/src/client/conversations/ChatLayout.tsx +7 -3
- package/src/client/conversations/ConversationBrief.tsx +17 -6
- package/src/client/conversations/ConversationChildAgents.tsx +5 -5
- package/src/client/conversations/ConversationComposer.tsx +26 -12
- package/src/client/conversations/ConversationDetails.tsx +147 -62
- package/src/client/conversations/ConversationEventDetails.tsx +141 -0
- package/src/client/conversations/ConversationEventLog.tsx +150 -129
- package/src/client/conversations/ConversationHeader.tsx +13 -7
- package/src/client/conversations/ConversationHeaderActions.tsx +97 -93
- package/src/client/conversations/ConversationHomeList.tsx +1 -1
- package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
- package/src/client/conversations/ConversationMeta.tsx +55 -88
- package/src/client/conversations/ConversationPage.tsx +220 -101
- package/src/client/conversations/ConversationSidebar.tsx +49 -29
- package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
- package/src/client/conversations/ConversationWatches.tsx +173 -0
- package/src/client/conversations/ConversationWorkspace.tsx +12 -22
- package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
- package/src/client/conversations/DetailsList.tsx +139 -0
- package/src/client/conversations/EventDetails.tsx +42 -8
- package/src/client/conversations/EventUsage.tsx +99 -74
- package/src/client/conversations/ForkConversationButton.tsx +27 -16
- package/src/client/conversations/ObjectCard.tsx +20 -8
- package/src/client/conversations/PendingMailboxStack.tsx +52 -38
- package/src/client/conversations/README.md +89 -13
- package/src/client/conversations/ShareConversationButton.tsx +28 -17
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
- package/src/client/conversations/ToolFrame.tsx +36 -52
- package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
- package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
- package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
- package/src/client/conversations/TranscriptEventView.tsx +35 -16
- package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
- package/src/client/conversations/TranscriptLoading.tsx +1 -1
- package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
- package/src/client/conversations/TranscriptMessageContextView.tsx +35 -18
- package/src/client/conversations/TranscriptMessageView.tsx +6 -1
- package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
- package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
- package/src/client/conversations/TranscriptSummary.tsx +34 -2
- package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
- package/src/client/conversations/TranscriptToolView.tsx +1 -1
- package/src/client/conversations/TranscriptTurnContextView.tsx +144 -65
- package/src/client/conversations/TranscriptView.tsx +63 -27
- package/src/client/conversations/eventLog.ts +58 -0
- package/src/client/conversations/eventTime.ts +60 -0
- package/src/client/conversations/queries.ts +29 -0
- package/src/client/conversations/transcriptBottomPinning.ts +34 -0
- package/src/client/conversations/transcriptMentions.tsx +18 -5
- package/src/client/format.ts +5 -0
- package/src/client/pages/ConnectionsPage.tsx +2 -2
- package/src/client/pages/PersonalTokensPage.tsx +4 -4
- package/src/client/pages/SettingsPage.tsx +9 -10
- package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
- package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
- package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
- package/src/client/pages/automations/AutomationDetails.tsx +193 -0
- package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
- package/src/client/pages/automations/AutomationEditor.tsx +41 -29
- package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
- package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
- package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
- package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
- package/src/client/pages/automations/AutomationFilters.tsx +189 -74
- package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
- package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
- package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
- package/src/client/pages/automations/AutomationRow.tsx +12 -138
- package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
- package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
- package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
- package/src/client/pages/automations/AutomationStatus.tsx +201 -0
- package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
- package/src/client/pages/automations/AutomationsPage.tsx +80 -68
- package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
- package/src/client/pages/automations/README.md +57 -0
- package/src/client/pages/automations/TriggerFilters.tsx +22 -0
- package/src/client/pages/automations/automationFormat.ts +37 -23
- package/src/client/pages/code/CodeActivityChart.tsx +59 -101
- package/src/client/pages/code/CodePage.tsx +52 -55
- package/src/client/pages/code/RepositoryPage.tsx +6 -8
- package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
- package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
- package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
- package/src/client/pages/memory/MemoryDetails.tsx +218 -0
- package/src/client/pages/memory/MemoryPage.tsx +168 -112
- package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
- package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
- package/src/client/pages/memory/memoryRecord.ts +1 -1
- package/src/client/pages/people/ContributionGrid.tsx +23 -16
- package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
- package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
- package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
- package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
- package/src/client/pages/system/GuardianActivity.tsx +1 -2
- package/src/client/pages/system/PluginBarChart.tsx +106 -87
- package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
- package/src/client/pages/system/README.md +23 -0
- package/src/client/pages/system/SystemNavigation.tsx +5 -1
- package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
- package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
- package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
- package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
- package/src/client/pages/system/WorkspaceList.tsx +20 -30
- package/src/client/pages/system/WorkspacesPage.tsx +117 -119
- package/src/client/pages/system/sandboxSize.ts +8 -0
- package/src/client/pages/system/workspaceQueries.ts +53 -0
- package/src/client/pages/user/PluginUserPage.tsx +51 -2
- package/src/client/pages/user/pluginUserPageData.ts +1 -6
- package/src/client/styles.ts +4 -0
- package/src/client.tsx +7 -1
- package/src/mock-reporting/automation-collection.ts +4 -2
- package/src/mock-reporting/fixtures.ts +23 -7
- package/src/mock-reporting/routes.ts +12 -0
- package/src/mock-reporting/watches.ts +94 -0
- package/src/shell.ts +4 -9
- package/src/tailwind.css +0 -10
- package/src/client/components/Button.tsx +0 -118
- package/src/client/components/Field.tsx +0 -53
- package/src/client/components/SegmentedTabs.tsx +0 -119
- package/src/client/components/Select.tsx +0 -52
- package/src/client/components/Skeleton.tsx +0 -17
- package/src/client/components/TextInput.tsx +0 -58
- package/src/client/components/Tooltip.tsx +0 -216
- package/src/client/components/charts/useChartLayout.ts +0 -27
- package/src/client/components/ui/sheet.LICENSE +0 -21
- package/src/client/conversations/ConversationDetailsFrame.tsx +0 -119
- package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
- package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
- package/src/client/pages/dev/ChartFixtures.tsx +0 -325
- package/src/client/pages/dev/ComponentsPage.tsx +0 -899
- package/src/client/pages/dev/ConversationFixture.tsx +0 -231
- package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
- package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
- package/src/client/pages/dev/SelectFixtures.tsx +0 -62
- package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
- package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
- package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
- package/src/client/pages/system/SnapshotSummary.tsx +0 -78
|
@@ -1,33 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { memo, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
1
|
+
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
3
2
|
import { createPortal } from "react-dom";
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import { Skeleton } from "../components/ui/skeleton";
|
|
5
|
+
import { Toggle } from "../components/ui/toggle";
|
|
6
|
+
import { useEventTime } from "./eventTime";
|
|
7
|
+
import { SearchInput } from "../components/SearchInput";
|
|
6
8
|
import { cn } from "../styles";
|
|
7
9
|
import type { ConversationTranscript } from "../types";
|
|
8
10
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
adjacentEventLogSeqs,
|
|
12
|
+
eventLogRows,
|
|
11
13
|
eventLogTone,
|
|
12
|
-
|
|
14
|
+
filterEventLogRows,
|
|
13
15
|
} from "./eventLog";
|
|
14
|
-
import {
|
|
15
|
-
import { ForkConversationButton } from "./ForkConversationButton";
|
|
16
|
+
import { ConversationEventDetails } from "./ConversationEventDetails";
|
|
16
17
|
import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
|
|
17
18
|
|
|
18
19
|
const rowClass =
|
|
19
|
-
"grid grid-cols-[12ch_minmax(0,1fr)
|
|
20
|
+
"grid grid-cols-[12ch_minmax(0,1fr)] items-baseline gap-x-3 px-4 @min-[32rem]:grid-cols-[12ch_17ch_minmax(0,1fr)]";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Show every reporting event in sequence order, outside the transcript reducer.
|
|
23
|
-
* Pass `onSelectedSeqChange` to own
|
|
24
|
+
* Pass `onSelectedSeqChange` to own selection and render details beside the log.
|
|
25
|
+
* Standalone transcripts keep a local selection and show an overlay.
|
|
24
26
|
*/
|
|
25
27
|
export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
26
28
|
conversation: ConversationTranscript;
|
|
29
|
+
onSearchChange(value: string): void;
|
|
27
30
|
onSelectedSeqChange?(seq: number | undefined): void;
|
|
28
31
|
selectedSeq?: number;
|
|
29
32
|
}) {
|
|
30
33
|
const { conversation } = props;
|
|
34
|
+
const time = useEventTime();
|
|
31
35
|
const search = useTranscriptSearch();
|
|
32
36
|
const [localSelectedSeq, setLocalSelectedSeq] = useState<number>();
|
|
33
37
|
const selectedSeq = props.onSelectedSeqChange
|
|
@@ -35,31 +39,14 @@ export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
|
35
39
|
: localSelectedSeq;
|
|
36
40
|
const setSelectedSeq = props.onSelectedSeqChange ?? setLocalSelectedSeq;
|
|
37
41
|
const listRef = useRef<HTMLOListElement>(null);
|
|
38
|
-
//
|
|
42
|
+
// Clicked rows are visible. Reveal links and keyboard selections after layout.
|
|
39
43
|
const revealedSeqRef = useRef<number>(undefined);
|
|
40
|
-
const titleId = useId();
|
|
41
44
|
const events = conversation.events;
|
|
42
|
-
const rows = useMemo(
|
|
43
|
-
() =>
|
|
44
|
-
events.map((event) => ({
|
|
45
|
-
event,
|
|
46
|
-
model: eventLogModel(event),
|
|
47
|
-
usage: eventLogUsage(event),
|
|
48
|
-
summary: eventLogSummary(event.data).replace(/\s+/g, " ").slice(0, 300),
|
|
49
|
-
})),
|
|
50
|
-
[events],
|
|
51
|
-
);
|
|
45
|
+
const rows = useMemo(() => eventLogRows(events), [events]);
|
|
52
46
|
// Large payloads are serialized only for an active search or the open entry.
|
|
53
47
|
const visibleRows = useMemo(
|
|
54
|
-
() =>
|
|
55
|
-
|
|
56
|
-
? rows.filter(({ event, summary, usage }) =>
|
|
57
|
-
`${summary} ${usage} ${JSON.stringify(event)}`
|
|
58
|
-
.toLowerCase()
|
|
59
|
-
.includes(search.normalizedQuery),
|
|
60
|
-
)
|
|
61
|
-
: rows,
|
|
62
|
-
[rows, search.active, search.normalizedQuery],
|
|
48
|
+
() => filterEventLogRows(rows, search.normalizedQuery),
|
|
49
|
+
[rows, search.normalizedQuery],
|
|
63
50
|
);
|
|
64
51
|
// Resolve the selection from current data so polling cannot leave stale details.
|
|
65
52
|
const selected = events.find((event) => event.seq === selectedSeq);
|
|
@@ -72,7 +59,7 @@ export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
|
72
59
|
);
|
|
73
60
|
if (!row) return;
|
|
74
61
|
revealedSeqRef.current = selectedSeq;
|
|
75
|
-
row.scrollIntoView({ block: "
|
|
62
|
+
row.scrollIntoView({ block: "nearest" });
|
|
76
63
|
}, [selectedSeq, visibleRows]);
|
|
77
64
|
|
|
78
65
|
if (conversation.eventHistory.status === "expired") {
|
|
@@ -85,54 +72,89 @@ export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
|
85
72
|
|
|
86
73
|
return (
|
|
87
74
|
<section aria-label="Conversation event log" className="@container min-w-0">
|
|
88
|
-
<div className="
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
75
|
+
<div className="sticky top-0 z-10 bg-dashboard-bg">
|
|
76
|
+
<div className="flex flex-wrap items-center gap-2 border-b border-dashboard-border px-4 py-2">
|
|
77
|
+
<SearchInput
|
|
78
|
+
className="min-w-32 flex-1 @max-[28rem]:basis-full"
|
|
79
|
+
label="Search events"
|
|
80
|
+
onChange={props.onSearchChange}
|
|
81
|
+
placeholder="Search events…"
|
|
82
|
+
size="compact"
|
|
83
|
+
value={search.query}
|
|
84
|
+
/>
|
|
85
|
+
<div className="ml-auto flex items-center gap-3 whitespace-nowrap text-xs text-dashboard-text-muted @max-[28rem]:w-full @max-[28rem]:justify-between">
|
|
86
|
+
<span role="status">
|
|
87
|
+
{search.active
|
|
88
|
+
? `${visibleRows.length} of ${events.length} loaded events`
|
|
89
|
+
: `${events.length} loaded events`}
|
|
90
|
+
</span>
|
|
91
|
+
<Toggle
|
|
92
|
+
aria-label="Use local time"
|
|
93
|
+
onPressedChange={time.toggle}
|
|
94
|
+
pressed={time.local}
|
|
95
|
+
title={time.title}
|
|
96
|
+
>
|
|
97
|
+
<span className="max-w-32 truncate">{time.label}</span>
|
|
98
|
+
</Toggle>
|
|
99
|
+
</div>
|
|
108
100
|
</div>
|
|
101
|
+
<EventLogColumns />
|
|
102
|
+
</div>
|
|
103
|
+
<div className="font-mono text-xs">
|
|
109
104
|
<ol
|
|
110
105
|
aria-label="Events"
|
|
111
106
|
className="m-0 list-none divide-y divide-dashboard-border-subtle p-0"
|
|
112
107
|
ref={listRef}
|
|
113
108
|
>
|
|
114
|
-
{visibleRows.map(({ event, summary,
|
|
115
|
-
<li
|
|
109
|
+
{visibleRows.map(({ event, summary, metadata }, index) => (
|
|
110
|
+
<li
|
|
111
|
+
className="scroll-mt-32 scroll-mb-2"
|
|
112
|
+
data-event-seq={event.seq}
|
|
113
|
+
key={event.seq}
|
|
114
|
+
>
|
|
116
115
|
<button
|
|
117
|
-
aria-
|
|
116
|
+
aria-expanded={selectedSeq === event.seq}
|
|
118
117
|
aria-label={`Event ${event.seq}: ${event.data.type}`}
|
|
119
118
|
className={cn(
|
|
120
119
|
rowClass,
|
|
121
|
-
"min-h-11 w-full cursor-pointer border-0 bg-transparent py-2 text-left leading-5 hover:bg-dashboard-fill-hover active:bg-dashboard-fill-strong focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus @min-[
|
|
122
|
-
selectedSeq === event.seq &&
|
|
120
|
+
"relative min-h-11 w-full cursor-pointer border-0 bg-transparent py-2 text-left leading-5 hover:bg-dashboard-fill-hover active:bg-dashboard-fill-strong focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus @min-[32rem]:min-h-9 @min-[32rem]:py-1.5",
|
|
121
|
+
selectedSeq === event.seq &&
|
|
122
|
+
"bg-dashboard-fill-strong before:absolute before:inset-y-0 before:left-0 before:w-0.5 before:bg-dashboard-accent before:content-['']",
|
|
123
123
|
)}
|
|
124
124
|
onClick={() => {
|
|
125
125
|
revealedSeqRef.current = event.seq;
|
|
126
126
|
setSelectedSeq(event.seq);
|
|
127
127
|
}}
|
|
128
|
+
onKeyDown={(keyEvent) => {
|
|
129
|
+
if (
|
|
130
|
+
keyEvent.altKey ||
|
|
131
|
+
keyEvent.ctrlKey ||
|
|
132
|
+
keyEvent.metaKey ||
|
|
133
|
+
keyEvent.shiftKey ||
|
|
134
|
+
(keyEvent.key !== "ArrowUp" && keyEvent.key !== "ArrowDown")
|
|
135
|
+
)
|
|
136
|
+
return;
|
|
137
|
+
keyEvent.preventDefault();
|
|
138
|
+
const next =
|
|
139
|
+
visibleRows[
|
|
140
|
+
index + (keyEvent.key === "ArrowDown" ? 1 : -1)
|
|
141
|
+
];
|
|
142
|
+
if (!next) return;
|
|
143
|
+
setSelectedSeq(next.event.seq);
|
|
144
|
+
listRef.current
|
|
145
|
+
?.querySelector<HTMLButtonElement>(
|
|
146
|
+
`[data-event-seq="${next.event.seq}"] button`,
|
|
147
|
+
)
|
|
148
|
+
?.focus({ preventScroll: true });
|
|
149
|
+
}}
|
|
128
150
|
type="button"
|
|
129
151
|
>
|
|
130
152
|
<time
|
|
131
153
|
className="tabular-nums text-dashboard-text-muted"
|
|
132
154
|
dateTime={event.createdAt}
|
|
133
|
-
title={event.createdAt}
|
|
155
|
+
title={time.formatTimestamp(event.createdAt)}
|
|
134
156
|
>
|
|
135
|
-
{event.createdAt
|
|
157
|
+
{time.formatClock(event.createdAt)}
|
|
136
158
|
</time>
|
|
137
159
|
<span
|
|
138
160
|
className={cn("truncate", eventLogTone(event.data))}
|
|
@@ -140,50 +162,19 @@ export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
|
140
162
|
>
|
|
141
163
|
<HighlightText text={event.data.type} />
|
|
142
164
|
</span>
|
|
143
|
-
<span className="col-span-2 row-start-2 grid min-w-0 gap-
|
|
144
|
-
<span className="flex min-w-0 flex-wrap items-baseline gap-x-2">
|
|
145
|
-
<span
|
|
146
|
-
className={cn(
|
|
147
|
-
"break-all",
|
|
148
|
-
model
|
|
149
|
-
? "font-semibold text-violet-300"
|
|
150
|
-
: "text-dashboard-text-muted",
|
|
151
|
-
)}
|
|
152
|
-
>
|
|
153
|
-
<HighlightText
|
|
154
|
-
text={model?.modelId ?? "Model not recorded"}
|
|
155
|
-
/>
|
|
156
|
-
</span>
|
|
157
|
-
{model?.modelProfile ? (
|
|
158
|
-
<span className="text-dashboard-text-muted">
|
|
159
|
-
<HighlightText text={model.modelProfile} />
|
|
160
|
-
</span>
|
|
161
|
-
) : null}
|
|
162
|
-
{model?.reasoningLevel ? (
|
|
163
|
-
<span className="text-dashboard-text-muted">
|
|
164
|
-
<HighlightText
|
|
165
|
-
text={`${model.reasoningLevel} reasoning`}
|
|
166
|
-
/>
|
|
167
|
-
</span>
|
|
168
|
-
) : null}
|
|
169
|
-
</span>
|
|
165
|
+
<span className="col-span-2 row-start-2 grid min-w-0 gap-0.5 text-dashboard-text @min-[32rem]:col-span-1 @min-[32rem]:row-auto">
|
|
170
166
|
<span className="truncate" title={summary}>
|
|
171
167
|
<HighlightText text={summary} />
|
|
172
168
|
</span>
|
|
173
|
-
{
|
|
169
|
+
{metadata ? (
|
|
174
170
|
<span
|
|
175
|
-
className="text-dashboard-text-muted"
|
|
176
|
-
title=
|
|
171
|
+
className="truncate text-dashboard-text-muted"
|
|
172
|
+
title={metadata}
|
|
177
173
|
>
|
|
178
|
-
<HighlightText text={
|
|
174
|
+
<HighlightText text={metadata} />
|
|
179
175
|
</span>
|
|
180
176
|
) : null}
|
|
181
177
|
</span>
|
|
182
|
-
<ChevronRight
|
|
183
|
-
aria-hidden="true"
|
|
184
|
-
className="col-start-3 row-start-1 text-dashboard-text-muted @min-[48rem]:col-start-4"
|
|
185
|
-
size={14}
|
|
186
|
-
/>
|
|
187
178
|
</button>
|
|
188
179
|
</li>
|
|
189
180
|
))}
|
|
@@ -196,45 +187,75 @@ export const ConversationEventLog = memo(function ConversationEventLog(props: {
|
|
|
196
187
|
</p>
|
|
197
188
|
) : null}
|
|
198
189
|
</div>
|
|
199
|
-
{selected
|
|
190
|
+
{selected && !props.onSelectedSeqChange
|
|
200
191
|
? createPortal(
|
|
201
|
-
<
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<h2
|
|
206
|
-
className="m-0 break-words font-mono text-sm font-semibold text-dashboard-text"
|
|
207
|
-
id={titleId}
|
|
208
|
-
>
|
|
209
|
-
{selected.data.type}
|
|
210
|
-
</h2>
|
|
211
|
-
<p className="mb-0 mt-1 font-mono text-xs text-dashboard-text-muted">
|
|
212
|
-
{selected.createdAt}
|
|
213
|
-
</p>
|
|
214
|
-
</>
|
|
215
|
-
}
|
|
192
|
+
<ConversationEventDetails
|
|
193
|
+
overlay
|
|
194
|
+
conversation={conversation}
|
|
195
|
+
event={selected}
|
|
216
196
|
onClose={() => setSelectedSeq(undefined)}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
>
|
|
221
|
-
{conversation.canFork &&
|
|
222
|
-
selected.data.type === "message" &&
|
|
223
|
-
selected.data.role === "assistant" &&
|
|
224
|
-
!selected.data.redacted ? (
|
|
225
|
-
<div className="mb-3 flex items-center gap-2 text-sm">
|
|
226
|
-
<ForkConversationButton
|
|
227
|
-
conversationId={conversation.conversationId}
|
|
228
|
-
messageId={selected.data.messageId}
|
|
229
|
-
/>
|
|
230
|
-
<span>Fork after this reply</span>
|
|
231
|
-
</div>
|
|
232
|
-
) : null}
|
|
233
|
-
<EventDetails key={selected.seq} event={selected} />
|
|
234
|
-
</Drawer>,
|
|
197
|
+
onSelect={setSelectedSeq}
|
|
198
|
+
{...adjacentEventLogSeqs(visibleRows, selected.seq)}
|
|
199
|
+
/>,
|
|
235
200
|
document.body,
|
|
236
201
|
)
|
|
237
202
|
: null}
|
|
238
203
|
</section>
|
|
239
204
|
);
|
|
240
205
|
});
|
|
206
|
+
|
|
207
|
+
const loadingRowWidths = ["w-3/5", "w-2/5", "w-4/5", "w-1/2", "w-2/3", "w-1/3"];
|
|
208
|
+
|
|
209
|
+
/** Match the event log toolbar, columns, and rows while the transcript loads. */
|
|
210
|
+
export function ConversationEventLogLoading() {
|
|
211
|
+
return (
|
|
212
|
+
<section aria-busy="true" className="@container min-w-0">
|
|
213
|
+
<span className="sr-only" role="status">
|
|
214
|
+
Loading events
|
|
215
|
+
</span>
|
|
216
|
+
<div className="sticky top-0 z-10 bg-dashboard-bg">
|
|
217
|
+
<div className="flex flex-wrap items-center gap-2 border-b border-dashboard-border px-4 py-2">
|
|
218
|
+
<Skeleton className="h-9 min-w-32 flex-1 @max-[28rem]:basis-full" />
|
|
219
|
+
<Skeleton className="ml-auto h-3 w-24" />
|
|
220
|
+
</div>
|
|
221
|
+
<EventLogColumns />
|
|
222
|
+
</div>
|
|
223
|
+
<ol className="m-0 list-none divide-y divide-dashboard-border-subtle p-0">
|
|
224
|
+
{loadingRowWidths.map((width, index) => (
|
|
225
|
+
<li
|
|
226
|
+
className={cn(
|
|
227
|
+
rowClass,
|
|
228
|
+
"min-h-11 items-center gap-y-2 py-2 @min-[32rem]:min-h-9 @min-[32rem]:py-1.5",
|
|
229
|
+
)}
|
|
230
|
+
key={index}
|
|
231
|
+
>
|
|
232
|
+
<Skeleton className="h-3 w-[10ch]" />
|
|
233
|
+
<Skeleton className="h-3 w-[12ch]" />
|
|
234
|
+
<Skeleton
|
|
235
|
+
className={cn(
|
|
236
|
+
"col-span-2 row-start-2 h-3 @min-[32rem]:col-span-1 @min-[32rem]:row-auto",
|
|
237
|
+
width,
|
|
238
|
+
)}
|
|
239
|
+
/>
|
|
240
|
+
</li>
|
|
241
|
+
))}
|
|
242
|
+
</ol>
|
|
243
|
+
</section>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function EventLogColumns() {
|
|
248
|
+
return (
|
|
249
|
+
<div
|
|
250
|
+
aria-hidden="true"
|
|
251
|
+
className={cn(
|
|
252
|
+
rowClass,
|
|
253
|
+
"border-b border-dashboard-border py-2 font-mono text-xs text-dashboard-text-muted",
|
|
254
|
+
)}
|
|
255
|
+
>
|
|
256
|
+
<span>Time</span>
|
|
257
|
+
<span>Event</span>
|
|
258
|
+
<span className="hidden @min-[32rem]:block">Summary</span>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { Ellipsis, Menu } from "lucide-react";
|
|
11
11
|
|
|
12
12
|
import { SearchInput } from "../components/SearchInput";
|
|
13
|
+
import { Button } from "../components/ui/button";
|
|
13
14
|
import { cn } from "../styles";
|
|
14
15
|
import {
|
|
15
16
|
MobileHeaderActionsPortal,
|
|
@@ -53,11 +54,16 @@ export function ConversationHeader(props: {
|
|
|
53
54
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
54
55
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
55
56
|
const mobileMenuRef = useRef<HTMLDivElement>(null);
|
|
56
|
-
const searchOpenVisible =
|
|
57
|
+
const searchOpenVisible =
|
|
58
|
+
props.view === "rich" && (searchOpen || props.search.length > 0);
|
|
57
59
|
const openMobileNavigation = useOpenMobileNavigation();
|
|
58
60
|
|
|
59
61
|
useEffect(() => {
|
|
60
|
-
if (
|
|
62
|
+
if (
|
|
63
|
+
wasDetailsOpen.current &&
|
|
64
|
+
!detailsOpen &&
|
|
65
|
+
document.activeElement === document.body
|
|
66
|
+
) {
|
|
61
67
|
const trigger = window.matchMedia("(max-width: 767px)").matches
|
|
62
68
|
? menuButtonRef.current
|
|
63
69
|
: detailsButtonRef.current;
|
|
@@ -144,17 +150,17 @@ export function ConversationHeader(props: {
|
|
|
144
150
|
view={props.view}
|
|
145
151
|
/>
|
|
146
152
|
{openMobileNavigation ? (
|
|
147
|
-
<
|
|
148
|
-
className="mt-0.5
|
|
153
|
+
<Button
|
|
154
|
+
className="mt-0.5"
|
|
149
155
|
onClick={() => {
|
|
150
156
|
setMobileMenuOpen(false);
|
|
151
157
|
openMobileNavigation();
|
|
152
158
|
}}
|
|
153
|
-
|
|
159
|
+
size="menu"
|
|
154
160
|
>
|
|
155
161
|
<Menu aria-hidden="true" size={16} strokeWidth={2} />
|
|
156
162
|
App menu
|
|
157
|
-
</
|
|
163
|
+
</Button>
|
|
158
164
|
) : null}
|
|
159
165
|
</div>
|
|
160
166
|
) : null}
|
|
@@ -182,7 +188,7 @@ export function ConversationHeader(props: {
|
|
|
182
188
|
<MobileHeaderLivePortal>{liveIndicator}</MobileHeaderLivePortal>
|
|
183
189
|
<header
|
|
184
190
|
className={cn(
|
|
185
|
-
"
|
|
191
|
+
"relative z-10 border-b border-dashboard-border bg-dashboard-bg",
|
|
186
192
|
!showMobileHeader && "hidden md:block",
|
|
187
193
|
)}
|
|
188
194
|
>
|