@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
@@ -14,7 +14,7 @@ import { Drawer } from "../components/Drawer";
14
14
  import { SearchInput } from "../components/SearchInput";
15
15
  import { StatusChip } from "../components/StatusChip";
16
16
  import { subagentStatusTone } from "./ConversationChildAgents";
17
- import { CopyMarkdownButton } from "./CopyMarkdownButton";
17
+ import { CopyButton } from "../components/CopyButton";
18
18
  import {
19
19
  TranscriptSearchToggle,
20
20
  TranscriptViewToggle,
@@ -69,7 +69,8 @@ function SubagentTranscriptDrawerContent(props: {
69
69
  ? props.target.agentName
70
70
  : undefined;
71
71
  const startedAt = detail ? Date.parse(detail.startedAt) : undefined;
72
- const searchOpenVisible = searchOpen || search.length > 0;
72
+ const searchOpenVisible =
73
+ view === "rich" && (searchOpen || search.length > 0);
73
74
 
74
75
  const titleId = "subagent-transcript-drawer-title";
75
76
 
@@ -77,21 +78,25 @@ function SubagentTranscriptDrawerContent(props: {
77
78
  <Drawer
78
79
  actions={
79
80
  <>
80
- <TranscriptSearchToggle
81
- onClick={() => {
82
- if (searchOpenVisible) {
83
- setSearchOpen(false);
84
- if (search.length > 0) setSearch("");
85
- return;
86
- }
87
- setSearchOpen(true);
88
- }}
89
- open={searchOpenVisible}
90
- />
81
+ {view === "rich" ? (
82
+ <TranscriptSearchToggle
83
+ onClick={() => {
84
+ if (searchOpenVisible) {
85
+ setSearchOpen(false);
86
+ if (search.length > 0) setSearch("");
87
+ return;
88
+ }
89
+ setSearchOpen(true);
90
+ }}
91
+ open={searchOpenVisible}
92
+ />
93
+ ) : null}
91
94
  <TranscriptViewToggle onChange={setView} value={view} />
92
- <CopyMarkdownButton
95
+ <CopyButton
96
+ label="Copy as Markdown"
97
+ copyingLabel="Preparing Markdown"
93
98
  key={props.target.conversationId}
94
- getMarkdown={
99
+ getText={
95
100
  detail
96
101
  ? async () =>
97
102
  buildConversationMarkdown(
@@ -184,6 +189,7 @@ function SubagentTranscriptDrawerContent(props: {
184
189
  loadingPreviousPage={query.isLoadingPreviousPage}
185
190
  onLoadPreviousPage={query.loadPreviousPage}
186
191
  search={search}
192
+ onSearchChange={setSearch}
187
193
  transcript={detail}
188
194
  view={view}
189
195
  />
@@ -1,17 +1,17 @@
1
1
  import { useState, type ReactNode } from "react";
2
2
  import type { LucideIcon } from "lucide-react";
3
3
 
4
+ import {
5
+ TraceCollapsible,
6
+ TraceCollapsibleContent,
7
+ TraceCollapsibleTrigger,
8
+ } from "../components/ui/trace";
4
9
  import { cn } from "../styles";
5
10
  import {
6
11
  TranscriptHeadingMeta,
7
12
  TranscriptHeadingRow,
8
13
  } from "./TranscriptHeadingRow";
9
14
  import { useTranscriptSearch } from "./transcriptSearch";
10
- import { TranscriptSummary } from "./TranscriptSummary";
11
-
12
- /** Frame expanded transcript activity content below its row title. */
13
- export const transcriptActivityBodyClass =
14
- "ml-6 mt-1.5 min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel";
15
15
 
16
16
  /** Render the shared expandable/non-expandable frame for transcript tools. */
17
17
  export function ToolFrame(props: {
@@ -27,30 +27,22 @@ export function ToolFrame(props: {
27
27
  const { active: searchActive } = useTranscriptSearch();
28
28
  const [open, setOpen] = useState(false);
29
29
  const metaText = props.meta.join(" · ");
30
- const interactive = props.expandable ?? Boolean(props.children);
31
- const staticFrame = searchActive || !interactive;
30
+ const expandable = props.expandable ?? Boolean(props.children);
31
+ // Force-expand tool details during search so highlighted matches are visible.
32
+ const expanded = expandable && (searchActive || open);
32
33
  const Icon = props.icon;
33
34
  const row = (
34
35
  <TranscriptHeadingRow
36
+ className="flex-1"
35
37
  left={
36
38
  <>
37
39
  {props.signature}
38
- {props.mobileSummaryMeta ? (
40
+ {props.mobileSummaryMeta && !expanded ? (
39
41
  <>
40
- <span
41
- className={cn(
42
- "hidden text-dashboard-text-muted max-md:inline",
43
- !staticFrame && "max-md:group-open:hidden",
44
- )}
45
- >
42
+ <span className="hidden text-dashboard-text-muted max-md:inline">
46
43
  ·
47
44
  </span>
48
- <span
49
- className={cn(
50
- "hidden shrink-0 whitespace-nowrap text-dashboard-text-muted max-md:inline",
51
- !staticFrame && "max-md:group-open:hidden",
52
- )}
53
- >
45
+ <span className="hidden shrink-0 whitespace-nowrap text-dashboard-text-muted max-md:inline">
54
46
  {props.mobileSummaryMeta}
55
47
  </span>
56
48
  </>
@@ -59,7 +51,7 @@ export function ToolFrame(props: {
59
51
  }
60
52
  leftClassName={cn(
61
53
  "gap-x-1 gap-y-0.5",
62
- staticFrame ? "flex-wrap" : "flex-nowrap group-open:flex-wrap",
54
+ expandable && !expanded ? "flex-nowrap" : "flex-wrap",
63
55
  )}
64
56
  right={
65
57
  metaText ? (
@@ -72,54 +64,46 @@ export function ToolFrame(props: {
72
64
  />
73
65
  );
74
66
  const header = Icon ? (
75
- <div className="grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
67
+ <span className="grid min-w-0 flex-1 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
76
68
  <Icon
77
69
  aria-hidden="true"
78
70
  className={cn("size-3.5 justify-self-center", props.iconClassName)}
79
71
  strokeWidth={2}
80
72
  />
81
73
  {row}
82
- </div>
74
+ </span>
83
75
  ) : (
84
76
  row
85
77
  );
86
- const mobileMeta =
87
- metaText && props.children ? (
88
- <div className="hidden min-w-0 break-words border-b border-dashboard-border-subtle px-2.5 py-1.5 font-sans text-xs tabular-nums leading-snug text-dashboard-text-muted max-md:block">
89
- {metaText}
90
- </div>
91
- ) : null;
92
78
 
93
- const body = props.children ? (
94
- <div className={transcriptActivityBodyClass}>
95
- {mobileMeta}
96
- {props.children}
97
- </div>
98
- ) : null;
99
-
100
- // Force-expand tool details during search so highlighted matches are visible.
101
- if (staticFrame) {
79
+ if (!expandable) {
102
80
  return (
103
- <div className="min-w-0 max-w-full">
104
- <div className="block py-1.5 font-mono text-xs leading-tight text-dashboard-text-muted">
105
- {header}
106
- </div>
107
- {body}
81
+ <div className="flex min-w-0 max-w-full py-1.5 font-mono text-xs leading-tight text-dashboard-text-muted">
82
+ {header}
108
83
  </div>
109
84
  );
110
85
  }
111
86
 
112
87
  return (
113
- <details
114
- className="group min-w-0 max-w-full"
115
- open={open}
116
- onToggle={(event) => setOpen(event.currentTarget.open)}
88
+ <TraceCollapsible
89
+ className="max-w-full"
90
+ // Search holds rows open, so the row button is off until search ends.
91
+ disabled={searchActive}
92
+ open={expanded}
93
+ onOpenChange={setOpen}
117
94
  >
118
- <TranscriptSummary className="-mx-2 block font-mono text-xs leading-tight text-dashboard-text-muted">
95
+ <TraceCollapsibleTrigger className="-mx-2 w-auto font-mono text-xs leading-tight">
119
96
  {header}
120
- </TranscriptSummary>
121
- {/* Closed details hide DOM, but still mount React children and run Shiki. */}
122
- {open ? body : null}
123
- </details>
97
+ </TraceCollapsibleTrigger>
98
+ {/* The closed panel unmounts, so closed rows do not run Shiki. */}
99
+ <TraceCollapsibleContent>
100
+ {metaText ? (
101
+ <div className="hidden min-w-0 break-words border-b border-dashboard-border-subtle px-2.5 py-1.5 font-sans text-xs tabular-nums leading-snug text-dashboard-text-muted max-md:block">
102
+ {metaText}
103
+ </div>
104
+ ) : null}
105
+ {props.children}
106
+ </TraceCollapsibleContent>
107
+ </TraceCollapsible>
124
108
  );
125
109
  }
@@ -2,7 +2,11 @@ import { Fragment, useState, type ReactNode } from "react";
2
2
  import { ChevronRight } from "lucide-react";
3
3
 
4
4
  import { ShimmerText } from "../components/ShimmerText";
5
- import { Tooltip } from "../components/Tooltip";
5
+ import {
6
+ Tooltip,
7
+ TooltipContent,
8
+ TooltipTrigger,
9
+ } from "../components/ui/tooltip";
6
10
  import { formatMs } from "../format";
7
11
  import type { RenderedTranscriptEntry } from "./transcriptRenderModel";
8
12
  import { cn } from "../styles";
@@ -180,8 +184,12 @@ export function TranscriptActivityGroup(props: {
180
184
  setUserOpen(!open);
181
185
  }}
182
186
  >
183
- <Tooltip content={summary} placement="above">
184
- <span className="inline-flex min-w-0 max-w-full items-center gap-1">
187
+ <Tooltip>
188
+ <TooltipTrigger
189
+ render={
190
+ <span className="inline-flex min-w-0 max-w-full items-center gap-1" />
191
+ }
192
+ >
185
193
  <span className="min-w-0 truncate group-open/activity-run:hidden">
186
194
  <ShimmerText active={live}>{label}</ShimmerText>
187
195
  </span>
@@ -193,7 +201,8 @@ export function TranscriptActivityGroup(props: {
193
201
  className="size-3 shrink-0 opacity-55 transition-transform group-open/activity-run:rotate-90"
194
202
  strokeWidth={2.2}
195
203
  />
196
- </span>
204
+ </TooltipTrigger>
205
+ <TooltipContent>{summary}</TooltipContent>
197
206
  </Tooltip>
198
207
  </TranscriptSummary>
199
208
  <TranscriptActivityNesting.Provider value>
@@ -2,7 +2,8 @@ import { ArrowRight, ChevronRight } from "lucide-react";
2
2
  import { useId, useState } from "react";
3
3
  import type { ConversationDetailReport } from "@sentry/junior/api/schema";
4
4
 
5
- import { ButtonLink } from "../components/Button";
5
+ import { buttonVariants } from "../components/ui/button";
6
+ import { Link } from "react-router";
6
7
  import { ObjectIcon } from "../components/ObjectIcon";
7
8
  import { automationPath, formatRelativeTime } from "../format";
8
9
  import { messageRawText } from "./transcriptRenderModel";
@@ -70,13 +71,13 @@ export function TranscriptAutomationTriggerView(props: {
70
71
  <HighlightText text={name} />
71
72
  </span>
72
73
  {automationId ? (
73
- <ButtonLink
74
- className="h-8 shrink-0 text-xs"
74
+ <Link
75
+ className={cn(buttonVariants(), "h-8 shrink-0 text-xs")}
75
76
  to={automationPath(automationId)}
76
77
  >
77
78
  Open automation
78
79
  <ArrowRight aria-hidden="true" size={14} />
79
- </ButtonLink>
80
+ </Link>
80
81
  ) : null}
81
82
  </div>
82
83
  {details.length > 0 ? (
@@ -1,3 +1,11 @@
1
+ import { ChevronRight } from "lucide-react";
2
+
3
+ import {
4
+ Collapsible,
5
+ CollapsibleContent,
6
+ CollapsibleTrigger,
7
+ } from "../components/ui/collapsible";
8
+ import { dashboardDisclosureChevronClass } from "../styles";
1
9
  import { formatCompactNumber, formatMessageTimestamp } from "../format";
2
10
  import type { TranscriptViewContextEventPart } from "../types";
3
11
  import { TranscriptText } from "./TranscriptText";
@@ -39,18 +47,24 @@ export function TranscriptContextEventView(props: {
39
47
  : `Earlier context was summarized${compactionDetail}${compactionModel} before execution continued.`}
40
48
  </div>
41
49
  {event.summary ? (
42
- <details className="mt-2">
43
- <summary className="cursor-pointer select-none text-xs font-medium text-dashboard-text-muted">
44
- Continuation summary
45
- </summary>
46
- <div className="mt-1.5 whitespace-pre-wrap text-xs leading-relaxed text-dashboard-text-muted">
47
- <TranscriptText
48
- mentions={props.part.mentions ?? []}
49
- role="system"
50
- text={event.summary}
50
+ <Collapsible className="mt-2">
51
+ <CollapsibleTrigger className="group flex cursor-pointer select-none items-center gap-1 text-xs font-medium text-dashboard-text-muted focus-visible:outline-2 focus-visible:outline-dashboard-focus">
52
+ <ChevronRight
53
+ aria-hidden="true"
54
+ className={dashboardDisclosureChevronClass}
51
55
  />
52
- </div>
53
- </details>
56
+ Continuation summary
57
+ </CollapsibleTrigger>
58
+ <CollapsibleContent hiddenUntilFound>
59
+ <div className="mt-1.5 whitespace-pre-wrap text-xs leading-relaxed text-dashboard-text-muted">
60
+ <TranscriptText
61
+ mentions={props.part.mentions ?? []}
62
+ role="system"
63
+ text={event.summary}
64
+ />
65
+ </div>
66
+ </CollapsibleContent>
67
+ </Collapsible>
54
68
  ) : null}
55
69
  </article>
56
70
  );
@@ -1,11 +1,14 @@
1
1
  import { ChevronRight } from "lucide-react";
2
+ import { useState } from "react";
2
3
 
4
+ import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
5
+ import { cn, dashboardDisclosureChevronClass } from "../styles";
3
6
  import { MentionText } from "./transcriptMentions";
4
7
  import { messageRawText } from "./transcriptRenderModel";
5
- import { HighlightText } from "./transcriptSearch";
8
+ import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
6
9
  import { RedactedMarker } from "./TranscriptRedacted";
7
10
  import type { TranscriptViewMessage } from "../types";
8
- import { TranscriptSummary } from "./TranscriptSummary";
11
+ import { TranscriptSummaryTrigger } from "./TranscriptSummary";
9
12
 
10
13
  function EventTypeChip(props: { eventType: string }) {
11
14
  return (
@@ -25,6 +28,8 @@ function batchSummary(events: readonly { label?: string }[]): string {
25
28
 
26
29
  /** Render an Event Message whose heading expands its full text. */
27
30
  export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
31
+ const { active: searchActive } = useTranscriptSearch();
32
+ const [open, setOpen] = useState(false);
28
33
  const text = messageRawText(props.message);
29
34
  const redacted = props.message.parts.some(
30
35
  (part) => part.type === "text" && part.redacted,
@@ -35,33 +40,38 @@ export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
35
40
  const summary = isBatch
36
41
  ? batchSummary(events)
37
42
  : (props.message.trustedSummary ?? props.message.eventType ?? "");
43
+ // With text, the heading sits in the disclosure button, which cannot hold
44
+ // links.
45
+ const links = !text;
38
46
  const heading = (
39
47
  <span className="flex min-w-0 flex-col gap-1">
40
48
  <span className="flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
41
49
  <span className="min-w-0 break-words font-display text-sm font-semibold leading-6 text-dashboard-text">
42
- <MentionText mentions={mentions} text={summary} />
50
+ <MentionText links={links} mentions={mentions} text={summary} />
43
51
  </span>
44
52
  {!isBatch && props.message.eventType ? (
45
53
  <EventTypeChip eventType={props.message.eventType} />
46
54
  ) : null}
47
55
  </span>
48
56
  {isBatch ? (
49
- <ul className="flex min-w-0 flex-col gap-1">
57
+ <span className="flex min-w-0 flex-col gap-1" role="list">
50
58
  {events.map((event, index) => (
51
- <li
59
+ <span
52
60
  key={index}
61
+ role="listitem"
53
62
  className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs leading-5 text-dashboard-text-muted"
54
63
  >
55
64
  <span className="min-w-0 break-words">
56
65
  <MentionText
66
+ links={links}
57
67
  mentions={mentions}
58
68
  text={event.trustedSummary ?? event.eventType}
59
69
  />
60
70
  </span>
61
71
  <EventTypeChip eventType={event.eventType} />
62
- </li>
72
+ </span>
63
73
  ))}
64
- </ul>
74
+ </span>
65
75
  ) : null}
66
76
  </span>
67
77
  );
@@ -69,22 +79,31 @@ export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
69
79
  return (
70
80
  <div className="min-w-0 py-1">
71
81
  {text ? (
72
- <details className="group/event min-w-0">
73
- <TranscriptSummary
82
+ <Collapsible
83
+ className="min-w-0"
84
+ // Search holds the text open, so the heading button is off until
85
+ // search ends.
86
+ disabled={searchActive}
87
+ onOpenChange={setOpen}
88
+ open={searchActive || open}
89
+ >
90
+ <TranscriptSummaryTrigger
74
91
  flush
75
- className="flex items-start gap-2 text-dashboard-text-muted"
92
+ className="group flex items-start gap-2 text-dashboard-text-muted"
76
93
  >
77
94
  {heading}
78
95
  <ChevronRight
79
96
  aria-hidden="true"
80
- className="mt-1.5 size-3 shrink-0 transition-transform group-open/event:rotate-90"
97
+ className={cn(dashboardDisclosureChevronClass, "mt-1.5")}
81
98
  strokeWidth={2.2}
82
99
  />
83
- </TranscriptSummary>
84
- <pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border bg-dashboard-surface-panel px-3 py-2 font-sans text-xs leading-relaxed text-dashboard-text-muted">
85
- <HighlightText text={text} />
86
- </pre>
87
- </details>
100
+ </TranscriptSummaryTrigger>
101
+ <CollapsibleContent hiddenUntilFound>
102
+ <pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border bg-dashboard-surface-panel px-3 py-2 font-sans text-xs leading-relaxed text-dashboard-text-muted">
103
+ <HighlightText text={text} />
104
+ </pre>
105
+ </CollapsibleContent>
106
+ </Collapsible>
88
107
  ) : (
89
108
  <>
90
109
  {heading}
@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
2
2
 
3
3
  import { cn } from "../styles";
4
4
 
5
- /** Align transcript labels and metadata as one centered heading row. */
5
+ /** Align transcript labels and metadata as one centered heading row. Spans keep it valid inside a row button. */
6
6
  export function TranscriptHeadingRow(props: {
7
7
  className?: string;
8
8
  left: ReactNode;
@@ -14,31 +14,31 @@ export function TranscriptHeadingRow(props: {
14
14
  props.right !== undefined && props.right !== null && props.right !== false;
15
15
 
16
16
  return (
17
- <div
17
+ <span
18
18
  className={cn(
19
19
  "flex min-w-0 items-start justify-between gap-2 md:items-center md:gap-3",
20
20
  props.className,
21
21
  )}
22
22
  >
23
- <div
23
+ <span
24
24
  className={cn(
25
25
  "flex min-w-0 items-center gap-2 overflow-hidden",
26
26
  props.leftClassName,
27
27
  )}
28
28
  >
29
29
  {props.left}
30
- </div>
30
+ </span>
31
31
  {hasRight ? (
32
- <div
32
+ <span
33
33
  className={cn(
34
34
  "min-w-0 max-w-[60%] shrink text-right md:max-w-none md:shrink-0",
35
35
  props.rightClassName,
36
36
  )}
37
37
  >
38
38
  {props.right}
39
- </div>
39
+ </span>
40
40
  ) : null}
41
- </div>
41
+ </span>
42
42
  );
43
43
  }
44
44
 
@@ -1,5 +1,5 @@
1
1
  import { TranscriptRow, TranscriptRows } from "./TranscriptRows";
2
- import { Skeleton } from "../components/Skeleton";
2
+ import { Skeleton } from "../components/ui/skeleton";
3
3
 
4
4
  /** Match the usual transcript rhythm while the selected conversation loads. */
5
5
  export function TranscriptLoading() {
@@ -1,5 +1,13 @@
1
1
  import type { ReactNode } from "react";
2
2
 
3
+ import {
4
+ Table,
5
+ TableBody,
6
+ TableCell,
7
+ TableHead,
8
+ TableHeader,
9
+ TableRow,
10
+ } from "../components/ui/table";
3
11
  import { cn } from "../styles";
4
12
  import {
5
13
  findTranscriptMarkdownLinks,
@@ -184,51 +192,48 @@ function MarkdownTable(props: {
184
192
  );
185
193
 
186
194
  return (
187
- <div className="min-w-0 max-w-full overflow-x-auto rounded-md border border-dashboard-border bg-dashboard-fill-faint">
188
- <table className="w-max min-w-full border-collapse text-left text-sm">
189
- <thead className="bg-dashboard-overlay-soft">
190
- <tr>
195
+ <div className="min-w-0 max-w-full overflow-hidden rounded-md border border-dashboard-border bg-dashboard-fill-faint">
196
+ <Table className="w-max min-w-full">
197
+ <TableHeader className="bg-dashboard-overlay-soft">
198
+ <TableRow className="border-dashboard-border">
191
199
  {Array.from({ length: columnCount }, (_, index) => {
192
200
  const alignment = props.block.alignments[index] ?? null;
193
201
  return (
194
- <th
202
+ <TableHead
195
203
  className={cn(
196
- "whitespace-nowrap border-b border-dashboard-border px-2.5 py-1.5 font-sans text-xs font-medium text-dashboard-text-muted",
204
+ "px-2.5 py-1.5",
197
205
  tableCellAlignClass(alignment),
198
206
  )}
199
207
  key={`h-${index}`}
200
208
  scope="col"
201
209
  >
202
210
  {renderInlineMarkdown(props.block.headers[index] ?? "")}
203
- </th>
211
+ </TableHead>
204
212
  );
205
213
  })}
206
- </tr>
207
- </thead>
208
- <tbody>
214
+ </TableRow>
215
+ </TableHeader>
216
+ <TableBody>
209
217
  {props.block.rows.map((row, rowIndex) => (
210
- <tr
211
- className="border-b border-dashboard-border-subtle last:border-b-0"
212
- key={`r-${rowIndex}`}
213
- >
218
+ <TableRow key={`r-${rowIndex}`}>
214
219
  {Array.from({ length: columnCount }, (_, index) => {
215
220
  const alignment = props.block.alignments[index] ?? null;
216
221
  return (
217
- <td
222
+ <TableCell
218
223
  className={cn(
219
- "whitespace-nowrap px-2.5 py-1.5 align-top text-dashboard-text",
224
+ "px-2.5 py-1.5 align-top",
220
225
  tableCellAlignClass(alignment),
221
226
  )}
222
227
  key={`c-${rowIndex}-${index}`}
223
228
  >
224
229
  {renderInlineMarkdown(row[index] ?? "")}
225
- </td>
230
+ </TableCell>
226
231
  );
227
232
  })}
228
- </tr>
233
+ </TableRow>
229
234
  ))}
230
- </tbody>
231
- </table>
235
+ </TableBody>
236
+ </Table>
232
237
  </div>
233
238
  );
234
239
  }