@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.
Files changed (213) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -5
  3. package/dist/app.js +119 -35
  4. package/dist/client.js +145 -136
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +119 -35
  7. package/dist/tailwind.css +1 -1
  8. package/package.json +5 -4
  9. package/src/api/schema.ts +0 -1
  10. package/src/app.ts +5 -20
  11. package/src/client/App.tsx +29 -31
  12. package/src/client/api.ts +7 -0
  13. package/src/client/components/ActorAvatar.tsx +10 -22
  14. package/src/client/components/BottomSheet.tsx +12 -2
  15. package/src/client/components/ConnectionBanner.tsx +4 -3
  16. package/src/client/components/CopyButton.tsx +82 -0
  17. package/src/client/components/DetailsPanel.tsx +133 -0
  18. package/src/client/components/Drawer.tsx +15 -24
  19. package/src/client/components/EmptyTelemetry.tsx +5 -3
  20. package/src/client/components/FilterBar.tsx +16 -31
  21. package/src/client/components/ImageAttachment.tsx +49 -63
  22. package/src/client/components/InlineError.tsx +8 -4
  23. package/src/client/components/Metric.tsx +33 -23
  24. package/src/client/components/Notice.tsx +19 -26
  25. package/src/client/components/PageContentSkeleton.tsx +1 -1
  26. package/src/client/components/Pagination.tsx +27 -27
  27. package/src/client/components/ParticipantAvatarStack.tsx +43 -39
  28. package/src/client/components/ProfileMenu.tsx +27 -93
  29. package/src/client/components/README.md +103 -78
  30. package/src/client/components/SearchInput.tsx +51 -41
  31. package/src/client/components/SegmentedNav.tsx +1 -1
  32. package/src/client/components/ShimmerText.tsx +2 -6
  33. package/src/client/components/ThemeSwitcher.tsx +19 -15
  34. package/src/client/components/VersionDriftBanner.tsx +9 -7
  35. package/src/client/components/charts/ActivityChart.tsx +173 -288
  36. package/src/client/components/charts/CacheWrites.tsx +59 -37
  37. package/src/client/components/charts/InputCacheChart.tsx +137 -131
  38. package/src/client/components/charts/README.md +4 -4
  39. package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
  40. package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
  41. package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
  42. package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
  43. package/src/client/components/layout/DashboardHeader.tsx +44 -90
  44. package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
  45. package/src/client/components/layout/VisualViewportShell.tsx +2 -2
  46. package/src/client/components/ui/accordion.tsx +77 -0
  47. package/src/client/components/ui/alert-dialog.tsx +89 -0
  48. package/src/client/components/ui/alert.tsx +64 -0
  49. package/src/client/components/ui/avatar.tsx +53 -0
  50. package/src/client/components/ui/button.tsx +86 -0
  51. package/src/client/components/ui/chart.tsx +74 -0
  52. package/src/client/components/ui/checkbox.tsx +26 -0
  53. package/src/client/components/ui/collapsible.tsx +22 -0
  54. package/src/client/components/ui/dialog.tsx +66 -0
  55. package/src/client/components/ui/empty.tsx +32 -0
  56. package/src/client/components/ui/field.tsx +49 -0
  57. package/src/client/components/ui/input-group.tsx +96 -0
  58. package/src/client/components/ui/input.tsx +35 -0
  59. package/src/client/components/ui/native-select.tsx +57 -0
  60. package/src/client/components/ui/pagination.tsx +60 -0
  61. package/src/client/components/ui/popover.tsx +67 -0
  62. package/src/client/components/ui/radio-group.tsx +32 -0
  63. package/src/client/components/ui/sheet.tsx +13 -3
  64. package/src/client/components/ui/skeleton.tsx +19 -0
  65. package/src/client/components/ui/spinner.tsx +21 -0
  66. package/src/client/components/ui/table.tsx +101 -0
  67. package/src/client/components/ui/tabs.tsx +75 -0
  68. package/src/client/components/ui/textarea.tsx +17 -0
  69. package/src/client/components/ui/toast.tsx +215 -0
  70. package/src/client/components/ui/toggle-group.tsx +36 -0
  71. package/src/client/components/ui/toggle.tsx +37 -0
  72. package/src/client/components/ui/tooltip.tsx +168 -0
  73. package/src/client/components/ui/trace.tsx +96 -0
  74. package/src/client/conversations/ChatLayout.tsx +7 -3
  75. package/src/client/conversations/ConversationBrief.tsx +17 -6
  76. package/src/client/conversations/ConversationChildAgents.tsx +5 -5
  77. package/src/client/conversations/ConversationComposer.tsx +26 -12
  78. package/src/client/conversations/ConversationDetails.tsx +147 -62
  79. package/src/client/conversations/ConversationEventDetails.tsx +141 -0
  80. package/src/client/conversations/ConversationEventLog.tsx +150 -129
  81. package/src/client/conversations/ConversationHeader.tsx +13 -7
  82. package/src/client/conversations/ConversationHeaderActions.tsx +97 -93
  83. package/src/client/conversations/ConversationHomeList.tsx +1 -1
  84. package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
  85. package/src/client/conversations/ConversationMeta.tsx +55 -88
  86. package/src/client/conversations/ConversationPage.tsx +220 -101
  87. package/src/client/conversations/ConversationSidebar.tsx +49 -29
  88. package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
  89. package/src/client/conversations/ConversationWatches.tsx +173 -0
  90. package/src/client/conversations/ConversationWorkspace.tsx +12 -22
  91. package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
  92. package/src/client/conversations/DetailsList.tsx +139 -0
  93. package/src/client/conversations/EventDetails.tsx +42 -8
  94. package/src/client/conversations/EventUsage.tsx +99 -74
  95. package/src/client/conversations/ForkConversationButton.tsx +27 -16
  96. package/src/client/conversations/ObjectCard.tsx +20 -8
  97. package/src/client/conversations/PendingMailboxStack.tsx +52 -38
  98. package/src/client/conversations/README.md +89 -13
  99. package/src/client/conversations/ShareConversationButton.tsx +28 -17
  100. package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
  101. package/src/client/conversations/ToolFrame.tsx +36 -52
  102. package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
  103. package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
  104. package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
  105. package/src/client/conversations/TranscriptEventView.tsx +35 -16
  106. package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
  107. package/src/client/conversations/TranscriptLoading.tsx +1 -1
  108. package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
  109. package/src/client/conversations/TranscriptMessageContextView.tsx +35 -18
  110. package/src/client/conversations/TranscriptMessageView.tsx +6 -1
  111. package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
  112. package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
  113. package/src/client/conversations/TranscriptSummary.tsx +34 -2
  114. package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
  115. package/src/client/conversations/TranscriptToolView.tsx +1 -1
  116. package/src/client/conversations/TranscriptTurnContextView.tsx +144 -65
  117. package/src/client/conversations/TranscriptView.tsx +63 -27
  118. package/src/client/conversations/eventLog.ts +58 -0
  119. package/src/client/conversations/eventTime.ts +60 -0
  120. package/src/client/conversations/queries.ts +29 -0
  121. package/src/client/conversations/transcriptBottomPinning.ts +34 -0
  122. package/src/client/conversations/transcriptMentions.tsx +18 -5
  123. package/src/client/format.ts +5 -0
  124. package/src/client/pages/ConnectionsPage.tsx +2 -2
  125. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  126. package/src/client/pages/SettingsPage.tsx +9 -10
  127. package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
  128. package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
  129. package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
  130. package/src/client/pages/automations/AutomationDetails.tsx +193 -0
  131. package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
  132. package/src/client/pages/automations/AutomationEditor.tsx +41 -29
  133. package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
  134. package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
  135. package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
  136. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
  137. package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
  138. package/src/client/pages/automations/AutomationFilters.tsx +189 -74
  139. package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
  140. package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
  141. package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
  142. package/src/client/pages/automations/AutomationRow.tsx +12 -138
  143. package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
  144. package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
  145. package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
  146. package/src/client/pages/automations/AutomationStatus.tsx +201 -0
  147. package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
  148. package/src/client/pages/automations/AutomationsPage.tsx +80 -68
  149. package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
  150. package/src/client/pages/automations/README.md +57 -0
  151. package/src/client/pages/automations/TriggerFilters.tsx +22 -0
  152. package/src/client/pages/automations/automationFormat.ts +37 -23
  153. package/src/client/pages/code/CodeActivityChart.tsx +59 -101
  154. package/src/client/pages/code/CodePage.tsx +52 -55
  155. package/src/client/pages/code/RepositoryPage.tsx +6 -8
  156. package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
  157. package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
  158. package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
  159. package/src/client/pages/memory/MemoryDetails.tsx +218 -0
  160. package/src/client/pages/memory/MemoryPage.tsx +168 -112
  161. package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
  162. package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
  163. package/src/client/pages/memory/memoryRecord.ts +1 -1
  164. package/src/client/pages/people/ContributionGrid.tsx +23 -16
  165. package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
  166. package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
  167. package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
  168. package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
  169. package/src/client/pages/system/GuardianActivity.tsx +1 -2
  170. package/src/client/pages/system/PluginBarChart.tsx +106 -87
  171. package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
  172. package/src/client/pages/system/README.md +23 -0
  173. package/src/client/pages/system/SystemNavigation.tsx +5 -1
  174. package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
  175. package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
  176. package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
  177. package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
  178. package/src/client/pages/system/WorkspaceList.tsx +20 -30
  179. package/src/client/pages/system/WorkspacesPage.tsx +117 -119
  180. package/src/client/pages/system/sandboxSize.ts +8 -0
  181. package/src/client/pages/system/workspaceQueries.ts +53 -0
  182. package/src/client/pages/user/PluginUserPage.tsx +51 -2
  183. package/src/client/pages/user/pluginUserPageData.ts +1 -6
  184. package/src/client/styles.ts +4 -0
  185. package/src/client.tsx +7 -1
  186. package/src/mock-reporting/automation-collection.ts +4 -2
  187. package/src/mock-reporting/fixtures.ts +23 -7
  188. package/src/mock-reporting/routes.ts +12 -0
  189. package/src/mock-reporting/watches.ts +94 -0
  190. package/src/shell.ts +4 -9
  191. package/src/tailwind.css +0 -10
  192. package/src/client/components/Button.tsx +0 -118
  193. package/src/client/components/Field.tsx +0 -53
  194. package/src/client/components/SegmentedTabs.tsx +0 -119
  195. package/src/client/components/Select.tsx +0 -52
  196. package/src/client/components/Skeleton.tsx +0 -17
  197. package/src/client/components/TextInput.tsx +0 -58
  198. package/src/client/components/Tooltip.tsx +0 -216
  199. package/src/client/components/charts/useChartLayout.ts +0 -27
  200. package/src/client/components/ui/sheet.LICENSE +0 -21
  201. package/src/client/conversations/ConversationDetailsFrame.tsx +0 -119
  202. package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
  203. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
  204. package/src/client/pages/dev/ChartFixtures.tsx +0 -325
  205. package/src/client/pages/dev/ComponentsPage.tsx +0 -899
  206. package/src/client/pages/dev/ConversationFixture.tsx +0 -231
  207. package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
  208. package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
  209. package/src/client/pages/dev/SelectFixtures.tsx +0 -62
  210. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
  211. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
  212. package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
  213. package/src/client/pages/system/SnapshotSummary.tsx +0 -78
@@ -1,16 +1,19 @@
1
1
  import { ChevronRight } from "lucide-react";
2
+ import { useState } from "react";
2
3
 
4
+ import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
5
+ import { dashboardDisclosureChevronClass } from "../styles";
3
6
  import { formatMessageTimestamp, transcriptMessageActorLabel } from "../format";
4
7
  import type { ConversationTranscript, TranscriptViewMessage } from "../types";
5
8
  import {
6
9
  TranscriptHeadingMeta,
7
10
  TranscriptHeadingRow,
8
11
  } from "./TranscriptHeadingRow";
9
- import { HighlightText } from "./transcriptSearch";
12
+ import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
10
13
  import { messageRawText } from "./transcriptRenderModel";
11
14
  import { RedactedMarker } from "./TranscriptRedacted";
12
15
  import { TranscriptTurnContextView } from "./TranscriptTurnContextView";
13
- import { TranscriptSummary } from "./TranscriptSummary";
16
+ import { TranscriptSummaryTrigger } from "./TranscriptSummary";
14
17
 
15
18
  /** Render ambient conversation context that is not a primary chat bubble. */
16
19
  export function TranscriptMessageContextView(props: {
@@ -18,6 +21,8 @@ export function TranscriptMessageContextView(props: {
18
21
  message: TranscriptViewMessage;
19
22
  redacted?: boolean;
20
23
  }) {
24
+ const { active: searchActive } = useTranscriptSearch();
25
+ const [open, setOpen] = useState(false);
21
26
  const actor = transcriptMessageActorLabel(props.conversation, props.message);
22
27
  const timestamp = formatMessageTimestamp(props.message.timestamp);
23
28
  const text = messageRawText(props.message);
@@ -30,30 +35,39 @@ export function TranscriptMessageContextView(props: {
30
35
 
31
36
  return (
32
37
  <>
33
- <details
34
- className="group/message-context min-w-0 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 md:hidden"
38
+ <Collapsible
39
+ className="min-w-0 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 md:hidden"
35
40
  data-transcript-message-context
41
+ // Search holds the text open, so the heading button is off until
42
+ // search ends.
43
+ disabled={searchActive}
44
+ onOpenChange={setOpen}
45
+ open={searchActive || open}
36
46
  >
37
- <TranscriptSummary
47
+ <TranscriptSummaryTrigger
38
48
  flush
39
- className="flex items-center justify-between gap-2 font-sans text-xs font-medium text-dashboard-text-muted"
49
+ className="group flex items-center justify-between gap-2 font-sans text-xs font-medium text-dashboard-text-muted"
40
50
  >
41
51
  <span className="min-w-0 truncate">Context from {actor}</span>
42
52
  <ChevronRight
43
53
  aria-hidden="true"
44
- className="shrink-0 transition-transform group-open/message-context:rotate-90"
45
- size={14}
54
+ className={dashboardDisclosureChevronClass}
46
55
  />
47
- </TranscriptSummary>
48
- <div className="mt-2 whitespace-pre-wrap pt-2 text-sm leading-relaxed text-dashboard-text-subtle">
49
- {content}
50
- </div>
51
- {!props.redacted && props.message.contexts?.length ? (
52
- <div className="mt-2">
53
- <TranscriptTurnContextView contexts={props.message.contexts} />
56
+ </TranscriptSummaryTrigger>
57
+ <CollapsibleContent hiddenUntilFound>
58
+ <div className="mt-2 whitespace-pre-wrap pt-2 text-sm leading-relaxed text-dashboard-text-subtle">
59
+ {content}
54
60
  </div>
55
- ) : null}
56
- </details>
61
+ {!props.redacted && props.message.contexts?.length ? (
62
+ <div className="mt-2">
63
+ <TranscriptTurnContextView
64
+ contexts={props.message.contexts}
65
+ messageId={props.message.messageId}
66
+ />
67
+ </div>
68
+ ) : null}
69
+ </CollapsibleContent>
70
+ </Collapsible>
57
71
  <article
58
72
  className="hidden min-w-0 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 md:block"
59
73
  data-transcript-message-context
@@ -78,7 +92,10 @@ export function TranscriptMessageContextView(props: {
78
92
  </div>
79
93
  {!props.redacted && props.message.contexts?.length ? (
80
94
  <div className="mt-2">
81
- <TranscriptTurnContextView contexts={props.message.contexts} />
95
+ <TranscriptTurnContextView
96
+ contexts={props.message.contexts}
97
+ messageId={props.message.messageId}
98
+ />
82
99
  </div>
83
100
  ) : null}
84
101
  </article>
@@ -122,7 +122,12 @@ function messageAction(
122
122
  conversation: ConversationTranscript,
123
123
  ): ReactNode {
124
124
  if (message.role === "user" && message.contexts?.length) {
125
- return <TranscriptTurnContextView contexts={message.contexts} />;
125
+ return (
126
+ <TranscriptTurnContextView
127
+ contexts={message.contexts}
128
+ messageId={message.messageId}
129
+ />
130
+ );
126
131
  }
127
132
  if (
128
133
  conversation.canFork &&
@@ -1,15 +1,18 @@
1
+ import { useState } from "react";
1
2
  import { Lightbulb } from "lucide-react";
2
3
 
4
+ import {
5
+ TraceCollapsible,
6
+ TraceCollapsibleContent,
7
+ TraceCollapsibleTrigger,
8
+ } from "../components/ui/trace";
3
9
  import { formatMessageTimestamp } from "../format";
4
10
  import type { TranscriptViewReasoningPart } from "../types";
5
- import { cn } from "../styles";
6
11
  import {
7
12
  TranscriptHeadingMeta,
8
13
  TranscriptHeadingRow,
9
14
  } from "./TranscriptHeadingRow";
10
15
  import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
11
- import { TranscriptSummary } from "./TranscriptSummary";
12
- import { transcriptActivityBodyClass } from "./ToolFrame";
13
16
 
14
17
  /** Render reasoning collapsed with a short preview until expanded or searched. */
15
18
  export function TranscriptReasoningView(props: {
@@ -17,74 +20,57 @@ export function TranscriptReasoningView(props: {
17
20
  timestamp?: number;
18
21
  }) {
19
22
  const { active: searchActive } = useTranscriptSearch();
23
+ const [open, setOpen] = useState(false);
24
+ const expanded = searchActive || open;
20
25
  const rendered = props.part.redacted ? "Reasoning redacted" : props.part.text;
21
26
  const timestamp = formatMessageTimestamp(props.timestamp);
22
- const summary = (
23
- <>
24
- <span
25
- aria-label="Reasoning"
26
- className="inline-flex size-4 shrink-0 items-center justify-center text-violet-200/80"
27
- title="Reasoning"
28
- >
29
- <Lightbulb aria-hidden="true" size={14} strokeWidth={2} />
30
- </span>
31
- <TranscriptHeadingRow
32
- left={
33
- searchActive ? (
34
- <span className="block min-w-0 text-dashboard-text-muted">
35
- Reasoning
36
- </span>
37
- ) : (
38
- <>
39
- <span className="block min-w-0 truncate italic text-dashboard-text-muted group-open/reasoning:hidden">
40
- {rendered}
41
- </span>
42
- <span className="hidden min-w-0 text-dashboard-text-muted group-open/reasoning:inline">
43
- Reasoning
44
- </span>
45
- </>
46
- )
47
- }
48
- right={
49
- timestamp ? (
50
- <TranscriptHeadingMeta className="min-w-0 break-words text-xs tabular-nums text-dashboard-text-muted max-md:hidden">
51
- {timestamp}
52
- </TranscriptHeadingMeta>
53
- ) : undefined
54
- }
55
- rightClassName="min-w-0 max-md:hidden"
56
- />
57
- </>
58
- );
59
- const content = (
60
- <div className={cn(transcriptActivityBodyClass, "px-3 py-2.5")}>
61
- <div className="min-w-0 whitespace-pre-wrap break-words text-sm leading-relaxed text-dashboard-text-subtle">
62
- <HighlightText text={rendered} />
63
- </div>
64
- </div>
65
- );
66
-
67
- if (searchActive) {
68
- return (
69
- <div className={reasoningFrameClass()}>
70
- <div className="grid list-none grid-cols-[1rem_minmax(0,1fr)] items-center gap-2 py-1.5">
71
- {summary}
72
- </div>
73
- {content}
74
- </div>
75
- );
76
- }
77
27
 
78
28
  return (
79
- <details className={cn("group/reasoning", reasoningFrameClass())}>
80
- <TranscriptSummary className="-mx-2 grid grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
81
- {summary}
82
- </TranscriptSummary>
83
- {content}
84
- </details>
29
+ <TraceCollapsible
30
+ className="text-xs leading-tight"
31
+ // Search holds rows open, so the row button is off until search ends.
32
+ disabled={searchActive}
33
+ open={expanded}
34
+ onOpenChange={setOpen}
35
+ >
36
+ <TraceCollapsibleTrigger className="-mx-2 w-auto">
37
+ <span className="grid min-w-0 flex-1 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
38
+ <span
39
+ aria-label="Reasoning"
40
+ className="inline-flex size-4 shrink-0 items-center justify-center text-violet-200/80"
41
+ title="Reasoning"
42
+ >
43
+ <Lightbulb aria-hidden="true" size={14} strokeWidth={2} />
44
+ </span>
45
+ <TranscriptHeadingRow
46
+ left={
47
+ expanded ? (
48
+ <span className="block min-w-0 text-dashboard-text-muted">
49
+ Reasoning
50
+ </span>
51
+ ) : (
52
+ <span className="block min-w-0 truncate italic text-dashboard-text-muted">
53
+ {rendered}
54
+ </span>
55
+ )
56
+ }
57
+ right={
58
+ timestamp ? (
59
+ <TranscriptHeadingMeta className="min-w-0 break-words text-xs tabular-nums text-dashboard-text-muted max-md:hidden">
60
+ {timestamp}
61
+ </TranscriptHeadingMeta>
62
+ ) : undefined
63
+ }
64
+ rightClassName="min-w-0 max-md:hidden"
65
+ />
66
+ </span>
67
+ </TraceCollapsibleTrigger>
68
+ {/* Keep closed reasoning in the page, so browser find can reach it. */}
69
+ <TraceCollapsibleContent className="px-3 py-2.5" hiddenUntilFound>
70
+ <div className="min-w-0 whitespace-pre-wrap break-words text-sm leading-relaxed text-dashboard-text-subtle">
71
+ <HighlightText text={rendered} />
72
+ </div>
73
+ </TraceCollapsibleContent>
74
+ </TraceCollapsible>
85
75
  );
86
76
  }
87
-
88
- function reasoningFrameClass(): string {
89
- return "min-w-0 text-xs leading-tight";
90
- }
@@ -1,8 +1,9 @@
1
+ import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
1
2
  import { formatMessageTimestamp } from "../format";
2
3
  import type { TranscriptViewStructuredEventPart } from "../types";
3
4
  import { MentionText } from "./transcriptMentions";
4
5
  import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
5
- import { TranscriptSummary } from "./TranscriptSummary";
6
+ import { TranscriptSummaryTrigger } from "./TranscriptSummary";
6
7
 
7
8
  type TranscriptPresentationEventPart = TranscriptViewStructuredEventPart;
8
9
 
@@ -58,27 +59,34 @@ export function TranscriptStructuredEventView(props: {
58
59
  ))}
59
60
  </div>
60
61
  ) : null;
62
+ const collapsible = details.length > 0 && !search.active;
63
+ // The header can sit inside the row button, so it uses only inline elements
64
+ // and no links.
61
65
  const header = (
62
- <div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-2 max-md:grid-cols-[minmax(0,1fr)]">
63
- <div className="min-w-0">
64
- <div className="text-sm font-medium leading-6 text-dashboard-text">
66
+ <span className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-2 max-md:grid-cols-[minmax(0,1fr)]">
67
+ <span className="min-w-0">
68
+ <span className="block text-sm font-medium leading-6 text-dashboard-text">
65
69
  <HighlightText text={presentation.title} />
66
- </div>
70
+ </span>
67
71
  {presentation.preview ? (
68
- <div className="mt-0.5 truncate text-xs text-dashboard-text-muted">
69
- <MentionText mentions={mentions} text={presentation.preview} />
70
- </div>
72
+ <span className="mt-0.5 block truncate text-xs text-dashboard-text-muted">
73
+ <MentionText
74
+ links={!collapsible}
75
+ mentions={mentions}
76
+ text={presentation.preview}
77
+ />
78
+ </span>
71
79
  ) : null}
72
- </div>
80
+ </span>
73
81
  {timestamp ? (
74
82
  <span className="text-xs leading-6 tabular-nums text-dashboard-text-muted max-md:hidden">
75
83
  {timestamp}
76
84
  </span>
77
85
  ) : null}
78
- </div>
86
+ </span>
79
87
  );
80
88
 
81
- if (details.length === 0 || search.active) {
89
+ if (!collapsible) {
82
90
  return (
83
91
  <div className={surfaceClass}>
84
92
  {header}
@@ -87,9 +95,11 @@ export function TranscriptStructuredEventView(props: {
87
95
  );
88
96
  }
89
97
  return (
90
- <details className={`group/plugin-event ${surfaceClass}`}>
91
- <TranscriptSummary flush>{header}</TranscriptSummary>
92
- {body}
93
- </details>
98
+ <Collapsible className={surfaceClass}>
99
+ <TranscriptSummaryTrigger flush className="block">
100
+ {header}
101
+ </TranscriptSummaryTrigger>
102
+ <CollapsibleContent hiddenUntilFound>{body}</CollapsibleContent>
103
+ </Collapsible>
94
104
  );
95
105
  }
@@ -1,7 +1,11 @@
1
- import type { ComponentPropsWithoutRef } from "react";
1
+ import type { ComponentProps, ComponentPropsWithoutRef } from "react";
2
2
 
3
+ import { CollapsibleTrigger } from "../components/ui/collapsible";
3
4
  import { cn } from "../styles";
4
5
 
6
+ const summaryClass =
7
+ "cursor-pointer rounded-md px-2 py-1.5 transition-colors hover:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus";
8
+
5
9
  /** Keep hover and keyboard focus around a padded transcript cell. */
6
10
  export function TranscriptSummary({
7
11
  className,
@@ -15,10 +19,38 @@ export function TranscriptSummary({
15
19
  <summary
16
20
  {...props}
17
21
  className={cn(
18
- "cursor-pointer list-none rounded-md px-2 py-1.5 transition-colors hover:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus [&::-webkit-details-marker]:hidden",
22
+ summaryClass,
23
+ "list-none [&::-webkit-details-marker]:hidden",
19
24
  flush && "-mx-2 -my-1.5",
20
25
  className,
21
26
  )}
22
27
  />
23
28
  );
24
29
  }
30
+
31
+ /**
32
+ * Give a `Collapsible` trigger the same padding, hover, and focus as
33
+ * `TranscriptSummary`. The caller sets the display. Put only inline elements,
34
+ * such as `span`, inside the trigger.
35
+ */
36
+ export function TranscriptSummaryTrigger({
37
+ className,
38
+ flush = false,
39
+ ...props
40
+ }: Omit<ComponentProps<typeof CollapsibleTrigger>, "className"> & {
41
+ className?: string;
42
+ /** Extend padding around text that already sits on the transcript edge. */
43
+ flush?: boolean;
44
+ }) {
45
+ return (
46
+ <CollapsibleTrigger
47
+ {...props}
48
+ className={cn(
49
+ summaryClass,
50
+ "text-left disabled:cursor-default disabled:hover:bg-transparent",
51
+ flush ? "-mx-2 -my-1.5 w-[calc(100%+1rem)]" : "w-full",
52
+ className,
53
+ )}
54
+ />
55
+ );
56
+ }
@@ -1,6 +1,10 @@
1
1
  import { createContext, useContext, useState, type ReactNode } from "react";
2
2
 
3
- import { Tooltip } from "../components/Tooltip";
3
+ import {
4
+ Tooltip,
5
+ TooltipContent,
6
+ TooltipTrigger,
7
+ } from "../components/ui/tooltip";
4
8
  import {
5
9
  formatMessageTimestamp,
6
10
  formatRelativeMessageTimestamp,
@@ -51,18 +55,16 @@ export function TranscriptTimestamp(props: { value: number | undefined }) {
51
55
 
52
56
  const details = formatTranscriptTimestampDetails(props.value!);
53
57
  return (
54
- <Tooltip
55
- content={
58
+ <Tooltip>
59
+ <TooltipTrigger render={button} />
60
+ <TooltipContent>
56
61
  <span className="grid grid-cols-[auto_auto] gap-x-3">
57
62
  <span>Local</span>
58
63
  <span>{details.local}</span>
59
64
  <span>UTC</span>
60
65
  <span>{details.utc}</span>
61
66
  </span>
62
- }
63
- placement="above"
64
- >
65
- {button}
67
+ </TooltipContent>
66
68
  </Tooltip>
67
69
  );
68
70
  }
@@ -96,7 +96,7 @@ function ToolSignature(props: {
96
96
  <HighlightText text={props.name} />
97
97
  </ShimmerText>
98
98
  {props.preview && !searchActive ? (
99
- <code className="min-w-0 truncate font-[inherit] text-dashboard-text-muted group-open:hidden">
99
+ <code className="min-w-0 truncate font-[inherit] text-dashboard-text-muted group-aria-expanded/trace-collapsible-trigger:hidden">
100
100
  (<HighlightText text={props.preview} />)
101
101
  </code>
102
102
  ) : null}